Please don't restrict access to the companion-type!
Kevin Bourrillion
kevinb at google.com
Fri Jul 8 20:59:37 UTC 2022
I'm sympathetic to some of this. But I think I can accept the stake Brian
is putting in the ground. He says: a concrete class should be empowered to
provide for its own integrity, not merely count on its users to not hold it
wrong. If we must preserve that, then okay, we must.
I worry about decision fatigue for common cases, but I'm optimistic we have
a really good story here now:
1. First you will decide whether your class is a value class. I think this
should be as simple as "do you need any of the features identity would
provide?"
2. Then you will decide how much you want to expose its value
companion type. Is this as simple as "does it feel worth the (nonzero) risk
of bogus uninitialized instances floating around?"
3. And, if you know what you're doing, and you really need to optimize
heavily, you can make it non-atomic.
So I disagree with the main request (always-public companion types), but I
have a few comments/questions on the details.
On Thu, Jun 30, 2022 at 7:15 AM Brian Goetz <brian.goetz at oracle.com> wrote:
Your Accumulator example is correct, but I think you are overestimating the
> novelty of the problem. Arrays have always had a dynamic check; I can cast
> String[] to Object[] and hand that to you, if you try to put an Integer in
> it, you'll get an ASE. Handing out arrays for someone else to write to
> should always specify what the bounds on those writes are; "don't write
> nulls" is novel in degree but not in concept.
>
It is quite rare for public APIs to exchange arrays for purposes of writing
to them. It's a code smell. The safe and conscientious practice since the
beginning has been to only write to arrays you created yourself. I agree
with Brian that there's not much new here.
3. Let the compiler treat fields of companion-types like final fields
> today, i.e. enforce initialization.
>
> If this were possible to do reliably, we would have gone this way. But
> initializing final fields today has holes where the null is visible to the
> user, such as class initialization circularity and receiver escape. (And a
> reliable protocol is even harder for arrays.) Exposing a null in this way
> is bad, but exposing the zero in this way would be worse, because now every
> user has a way to get the zero and inject it into unsuspecting (and
> unguarded) implementation code.
>
I'd still like to understand what steps we can take to reduce the damage
here, even if they're not 100% solutions.
> There is simply no way we can reasonably expect everyone to write
> perfectly defensive code against a threat they don't fully understand and
> believe to be vanishingly rare -- and this is a perfect recipe for
> tomorrow's security exploits.
>
> 4. Provide the users with a convenient API for creating arrays with all
> elements initialized to a specific value.
>
>
> We explored this as well; it is a good start but ultimately not flexible
> enough to be "the solution". If a class has no good default, what value
> should it initialize array elements to? There's still no good default.
> And the model of "here's a lambda to initialize each element" is similarly
> an 80% solution.
>
fwiw, I'll still keep pushing on offering these, if I can somehow. I think
it's strange that they (create-and-fill, create-and-setAll) never got added
to Arrays by now. It is very nice when the user can isolate themselves
from the initialization gap.
The goal here is to let people write classes that can be used safely. If
> non-initialization is an mistake then we can make that mistake impossible.
> That's much better than trying to detect and recover from that mistake.
>
>
>
>
> -------- Forwarded Message --------
> Subject: Please don't restrict access to the companion-type!
> Date: Thu, 30 Jun 2022 09:33:42 +0200
> From: Gernot Neppert <mcnepp02 at googlemail.com> <mcnepp02 at googlemail.com>
> To: valhalla-spec-comments at openjdk.java.net
>
> I've been following the valhalla-development for a very long time, and
> have also posted quite a few comments, some of them raising valid concerns,
> some of them proving my ignorance.
>
> This comment hopefully falls into the first category:
>
> My concern is that allowing access-restriction for a value-type's
> "companion-type" is a severe case of "throwing the baby out with the
> bathwater".
>
> Yes, I know what it is supposed to achieve: prevent users from
> accidentally creating zero-initialized values for value-types "with no
> resonable default".
>
> However, the proposed solution of hiding the companion-type will force
> programmers to use the reference-type even if they do not want to.
> Please have a look at the following class "Accumulator". It assumes that
> "Sample" is a value-class in the same package with a non-public
> companion-type.
> The Javadoc must now explicitly mention some pitfalls that would not be
> there if "Sample.val" were accessible.
> Especially the necessary precaution about the returned array-type is
> rather ugly, right?!
>
> public class Accumulator {
> private Sample.val samples;
>
> /**
> Yields the samples that were taken.
> Note: the returned array is actually a "flat" array! No element can be
> null. While processing this array, do not try to set any of its elements to
> null, as that may trigger an ArrayStoreException!
> */
> public Sample[] samples() {
> return samples.clone();
> }
> }
>
> To sum it up, my proposal is:
>
> 1. Make the companion-type public always.
> 2. When introducing value-classes, document the risks of having
> "uninitialized" values under very specific circumstances (uninitialized
> fields, flat arrays).
> 3. Let the compiler treat fields of companion-types like final fields
> today, i.e. enforce initialization.
> 4. The risk of still encountering uninitialized fields is really really
> low, and is, btw, absolutely not new.
> 4. Provide the users with a convenient API for creating arrays with all
> elements initialized to a specific value.
> 5. In Java, one could possibly also use this currently disallowed syntax
> for creating initialized arrays: new Sample.val[20] { Sample.of("Hello") };
>
>
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-experts/attachments/20220708/94ad4c2f/attachment.htm>
More information about the valhalla-spec-experts
mailing list