[External] : Re: Revisiting default values

Gernot Neppert mcnepp02 at googlemail.com
Mon Mar 22 16:50:47 UTC 2021

Hi Brian, thank you for your response.

Two things: firstly, the function wouldn't need reified generics to 
work. If you rename it to "newInitializedArray" (which makes more sense 
in the first place) and document that "initializer" must not be null,
then you're done: the array's component-type would be the 
initializer.getClass() or initializer.getDeclaringClass() for enums.

secondly, the term "valid default" is misleading here. You wouldn't need 
such a universal value for every type. You'd just need a reasonable 
value to pass every time you call this function.
This value could well be different on every  invocation to suit your needs.

Am 20.03.2021 um 14:08 schrieb Brian Goetz:
> Also: I think you are conflating Buckets 2 and 3.  The method
>    static <T> T[] newArray(int dimension, T initializer)
> (which would also require reified generics to work) assumes that there 
> *is* a valid default you can pass it, it's just not zero.  Bucket 3, 
> which is more important than 2, is for the cases where there is no 
> reasonable default.

Yes, I fully agree that zero-default primitive classes should make up 
the majority of their kind. And of course, they also should be simple to 

However, nudging the developer to think hard whether zero-default is 
really fitting the bill in every single case is not overly burdening, I 

She would only have to add the two tokens "implements ZeroDefaultable" 
to her class-declaration - that's not too much to ask for :)

> On 3/20/2021 8:50 AM, Brian Goetz wrote:
>> I get where this is coming from, but I think it's misguided.
>> First, zero-hostile is a bad default.  The #1 use case for primitive 
>> classes is numerics, so the defaults should be tailored to their needs.

Hmm, not really. The usecase that I was presenting with the 
"Collection#toArray" example was explicitly about restricting the 
applicable types to the _sub-set_ of the "zero-defaultable" ones.

These types do, of course, include all reference-types, which follows 
naturally by having "interface IdentityObject extends ZeroDefaultable".

In such a case like the above, the type-bound <T extends 
ZeroDefaultable> fits perfectly.

>> Second, if the goal is to be able to generically abstract over 
>> nullable types (which include references and, in this model, 
>> zero-hostile primitives), what you really want is a _lower_ bound, 
>> and to generify over <T super Nullable>.  We don't have those, but 
>> distorting the hierarchy to wedge it into the bounds we have would 
>> likely be compounding an error.
>> That said, I like the idea that the type system could have something 
>> to say about array elements and construction.  Let me think on that 
>> some more.
>> On 3/20/2021 5:02 AM, Gernot Neppert wrote:
>>> I like your idea of having the programmer mark explicitly which 
>>> primitive classes should support the 'zero-default' case.
>>> However, I suggest to revert the meaning of the Marker interface to 
>>> 'ZeroDefaultable'.
>>> Why? Because it better matches the idea that an implementing type is 
>>> more capable than a type that does not implement it.
>>> Then it can be used as a type-bound for generic functions.
>>> As an example, have a look at Collection#toArray(IntFunction<T> 
>>> generator).
>>> This could then have the signature:
>>> <T extends Object & ZeroDefaultable> toArray(IntFunction<T> generator)
>>> The following compile-time rules would apply:
>>> For a type "ND" that does not implement 'ZeroDefaultable', the 
>>> compiler would ensure two things:
>>>  1. Force initialization of a member of that type, either at 
>>> declaration point or in a constructor, exactly as it does now for 
>>> final members.
>>>  2. Forbid the expression "new ND[N]". This also includes 
>>> disallowing the lambda-expression "ND[]::new".
>>> For being able to write generic code that create arrays of any type, 
>>> the JDK would provide a standard function in class java.util.Arrays 
>>> such as
>>> static <T> T[] newArray(int dimension, T initializer)
>>> This would leave us with the corner case of accessing uninitialized 
>>> variables of derived classes via constructors of base-classes (or 
>>> indirectly via virtual dispatch from such a constructor).
>>> In my observation, this case is extremely rare, and can and should 
>>> be neglected, as it represents a programming error already today.
>>> (Also posted this to valhalla-spec-observers)

More information about the valhalla-spec-observers mailing list