Fwd: Please don't restrict access to the companion-type!

Brian Goetz brian.goetz at oracle.com
Thu Jun 30 14:11:38 UTC 2022


This was received on the spec-comments list.  My comments here:

I'm a little mystified by this take, really.  Previously, you had 
"bucket 2" classes, which didn't even have a value projection; now all 
value classes have a value projection, but some have the option to 
encapsulate them.  But that is less restrictive than what we had before, 
so its odd to get this argument now?  If you don't want to restrict the 
value projection for your class, then you are free to expose it.  So it 
seems you are mostly afraid of _other_ class authors being too restrictive.

> Yes, I know what it is supposed to achieve: prevent users from 
> accidentally creating zero-initialized values for value-types "with no 
> resonable default".

The goal is bigger than this: it is to allow class authors to write safe 
classes.  If uninitialized values are OK (as they are with many 
numerics), then that's easy.  If they are not, then the class has two 
choices: write the class as to defend against uninitialized values as 
receivers and arguments (this may be hard), or encapsulate the 
initialization of flat values to ensure that bad values do not escape.  
Requiring the value projection always be public forces class authors 
down the first path, which they may not realize they need to do, and may 
well get wrong even if they try.

Secondarily, I think you are overestimating the downside of using the 
ref type; you probably have an outdated performance model that says "ref 
is as bad as boxing."  But the ref projection optimizes on the stack 
(parameters, returns, locals) almost as well as the val projection.  The 
major performance difference is in the heap.

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.

> 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.  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.

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>
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") };
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20220630/c3d512dd/attachment-0001.htm>


More information about the valhalla-spec-observers mailing list