Fwd: Null-restricted types: Why so complicated?
Quân Anh Mai
anhmdq at gmail.com
Fri Jan 19 16:47:51 UTC 2024
I forgot to cc valhalla-dev
---------- Forwarded message ---------
From: Quân Anh Mai <anhmdq at gmail.com>
Date: Sat, 20 Jan 2024 at 00:33
Subject: Re: Null-restricted types: Why so complicated?
To: John Bossons <jbossons at gmail.com>
Hi,
> But in Java idiom that means that a developer can invoke the public
implicit constructor, which will cause confusion.
An implicit constructor can be invoked like any other constructor, and it
will return an all-zero instance of the corresponding class.
> My further suggestion is that appending ! to a type should mean that the
default initialized value of an instance (all fields zero) is equivalent to
null, so that
> Range![] a = new Range![100]; // allocated with zero values
> System.out.println(a[5]); // throws NullPointerException (zero
fields)
> This better conforms to current idiom, where the initial initialization
is with nulls and the println invocation on a null array element or field
throws a NPE.
What is the value of this proposal? If you want the all-zero instance to be
equivalent to null, just do not have any constructor that initializes an
instance to that state. The whole point of null-restricted fields/variables
is to indicate that the field/variable is always valid.
I think you are having some confusion. Null-restriction is the property of
a variable/field, i.e. the property of the holder, not of the class itself.
The class having implicit constructors simply means that it allows the
existence of null-restricted fields/variables. The class can be used as
normal with non-null-restricted types. (e.g Range r = null;)
Regards,
Quan Anh
On Sat, 20 Jan 2024 at 00:09, John Bossons <jbossons at gmail.com> wrote:
> Thanks for your comments. I was not sufficiently explicit.
>
> Let me focus on implicit. I guess my dislike is of introducing a 'fake'
> constructor into the definition of a class. I say 'fake' because, as I
> understand it, the only purpose of the implicit constructor is to indicate
> to the JVM/compiler that a never-null instance can be created. But in Java
> idiom that means that a developer can invoke the public implicit
> constructor, which will cause confusion.
>
> Maybe it would be better to require a potentially null-restricted class to
> extend a marker interface ('extends NeverNullPossible'? Or maybe, looking
> ahead to my next comment, 'extends AllZerosIsNull'?). That would enable the
> compiler to catch an invalid use of the ! marker in a declaration, just as
> the proposed implicit constructor does, while conforming better to common
> Java idiom.
>
> My further suggestion is that appending ! to a type should mean that the
> default initialized value of an instance (all fields zero) is equivalent to
> null, so that
> Range![] a = new Range![100]; // allocated with zero values
> System.out.println(a[5]); // throws NullPointerException (zero
> fields)
> This better conforms to current idiom, where the initial initialization is
> with nulls and the println invocation on a null array element or field
> throws a NPE.
>
> As you say, my suggestion means runtime testing to determine if all fields
> are zero, which has a performance cost. This will only occur if the JVM
> implements the ! specification, which it presumably will only do if the
> object is small. And the cost will be small (I am presuming) relative to
> savings from allowing the memory footprint to match that of primitives. Am
> I wrong? There is value in conforming to current idiom.
>
> Turning to the LooselyConsistentValue, I withdraw my comments. I
> mistakenly presumed that its use would be required, which is false. It
> simply enables a single-threaded (or volatile-protected) application to
> allow additional inlining, which is harmless.
>
> John
>
> On Thu, Jan 18, 2024 at 4:56 PM - <liangchenblue at gmail.com> wrote:
>
>> Hi John,
>>
>> On Thu, Jan 18, 2024 at 2:30 PM John Bossons <jbossons at gmail.com> wrote:
>>
>>> Hi all,
>>>
>>> Maybe I am missing something, but the proposal seems to be trying to do
>>> too much.
>>>
>>> Specifically: Why not simply provide that appending ! to a type
>>> specification for an object (field, array element, or parameter) means that
>>> that the object is not only null-restricted but also never zero and
>>> necessarily non-atomic unless small?
>>>
>> First, a reminder that some objects cannot be non-atomic, mostly when
>> fields have dependencies/constraints on each other: if you have a range,
>> you cannot allow its lower bound to be larger than its upper bound.
>> Non-atomic representations cannot avoid this pitfall. Also you seem
>> to misunderstand non-atomic: if an object is non-atomic, each of its fields
>> can update independently from each other, so a 3-d position can be
>> non-atomic, but not so for a range. Non-atomicity is dangerous, and it
>> should not be the default. However, if an atomic class is small enough,
>> like OptionalInt (as now many architecture has like atomic handling of 16
>> bytes etc.) JVM may choose to apply non-atomic optimizations to them for
>> better performance without violating their object constraints.
>>
>>>
>>> Why complicate the specification with an implicit constructor that a
>>> developer will never explicitly invoke? Why permit a developer to 'opt in'
>>> to non-atomic?
>>>
>> The implicit constructor can always be called; its existence asks
>> programmers to affirm that the zero-filled inlined instance is a valid
>> instance. And this instance is different from a null, as null is a pointer,
>> yet the zero-instance has a different size defined by the class layout in
>> the stack/heap.
>>
>>>
>>> Sure, that means trying to read a zero value triggers a NPE. That just
>>> means that a type that can legitimately have a zero value cannot be
>>> specified as null-restricted, since a zero value (e.g. a {null, null} Name)
>>> is the equivalent of a null unrestricted value object. Why go beyond that?
>>> If a non-null zero value is possible, the type cannot be null-restricted
>>> and so can only be an unrestricted JEP 401 value type. End of story.
>>>
>> You see the inlined zero instance and the null pointer have different
>> sizes, and thus they are not exchangeable. Converting the inlined zero
>> instance to null to throw NPE is complex and hurtful to performance as you
>> will scan unrelated bits for almost every field access.
>>
>> And for unrestricted value type, yes, they exist and can possibly be
>> inlined as well if the restricted type is small enough (i.e. has space for
>> extra bit indicating nullity) But reminder, the nullity bit itself isn't
>> even non-atomic with (depends on) the rest of the object! You don't want
>> the nullity to indicate null while the rest of the object indicate some
>> sort of non-null value, which can happen in a non-atomic context.
>>
>>>
>>> With respect to non-atomic, what is new? Yes, unexpected instances may
>>> occur without synchronization if the object is larger than the word size of
>>> the implementation. Why do we need to extend a LooselyConsistentValue
>>> interface to know/permit that?
>>>
>> Unexpected instances don't occur without synchronization if you use
>> finals, such as in Java's String or immutable List.of(). These APIs may
>> capture any "permitted value" from the arrays passed in, but once
>> constructed, the captured value remains constant no matter which thread
>> observes the String/List object reference. (Technically, JVM implements
>> this with a store-store fence between end of field writes in the
>> constructor and object reference is shared anywhere, and a load-load fence
>> between object reference read and field read) Value classes is about the
>> safety of final fields in programming instead of the close encounter of
>> third kinds of synchronization, volatiles, and fences.
>>
>>>
>>> Can we not keep this 'simple' (if that word has meaning in this
>>> context)? What am I missing?
>>>
>> I think you are missing a bit about how the layout (inlining is
>> represented in memory) and value classes (the thread safety its final
>> offers) work, and what "non-atomic" means. Feel free to question more.
>>
>>>
>>> John
>>>
>>>
>>> --
>>> Phone: (416) 450-3584 (cell)
>>>
>>
>
> --
> Phone: (416) 450-3584 (cell)
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-dev/attachments/20240120/a8b1207a/attachment.htm>
More information about the valhalla-dev
mailing list