Civilizer - let's civilize those primitive types !

forax at univ-mlv.fr forax at univ-mlv.fr
Wed Jan 11 14:00:52 UTC 2023


> From: "Anderson Vasconcelos Pires" <andvasp at gmail.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "valhalla-dev" <valhalla-dev at openjdk.java.net>
> Sent: Wednesday, January 11, 2023 12:10:23 PM
> Subject: Re: Civilizer - let's civilize those primitive types !

> Hi Remi!

Hi Anderson, 

> Interesting... What would be the purpose of it? Create code that can have
> backward compatibility and get benefits when running with jdk-valhalla?

Mostly prototyping a proposal to remove Q-types (descriptor that starts with Q...;) and replace them by an attribute on methods and fields indicating if the value can be null. 
see [ https://mail.openjdk.org/pipermail/valhalla-spec-experts/2023-January/002217.html | https://mail.openjdk.org/pipermail/valhalla-spec-experts/2023-January/002217.html ] 

> Because I do not see differences between:

> value record Foo(int value) and @Value record Foo(int value);

yes, there is none (i hope) apart the fact that adding @ZeroDefault or not is a backward compatible change. 
Currently, there are three kind of class, identity class, value class and primitive class, i propose to have only two, identity class and value class. 
A zero-default class being a sub-category of value class. 

A zero-default class Foo does not work like a primitive class as defined in JEP 401. 
A zero-default class is nullable by default. So you can use it everywhere you want like an identity type or a value type (even in generics). 

Conceptually, the idea is to de-couple the notion of zero-default from the notion of nullability. 
By default a value type (zero-default or not) is nullable and you choose if you want the non-null version by adding @NonNull at use site. 
There is no notion of .val or .ref, if you want a field to be flattened, use a @Zero-Default and declare the field @NonNull. 

I will add that this is not my idea, this Brian's idea. 
I'm just proposing a way to achieve that in term of classfile representation / VM semantics. 

> How about the case below:

> @Value class A { int value;} // not record! before jdk-17 // value is not final
> too.

> var a = new A();
> a.value = 10; // I expect a compile error if we use value instead of @Value;

> Would I be obligated to make the value field final?

yes, the prototype does not do any verification that the compiler does, i'm too lazy for that but the VM will catch you and throw an Error. 

About the mutability of fields, fundamentally, value type is about saying, i give up the notion of identity, if you have no identity, you have no location in memory (you can have more than one if you prefer) so the VM is free to pass by reference or pass by value. So you can not mutate a field, because you can only do that if you have one location in memory. 

> Regards,
> Anderson.

regards, 
Rémi 

> On Tue, Jan 10, 2023 at 7:39 PM Remi Forax < [ mailto:forax at univ-mlv.fr |
> forax at univ-mlv.fr ] > wrote:

>> Hi all,
>> i've developed a small prototype of what the semantics for the next round could
>> be
>> [ https://github.com/forax/civilizer/ | https://github.com/forax/civilizer/ ]

>> The prototype works with the latest valhalla early access build
>> [ https://jdk.java.net/valhalla/ | https://jdk.java.net/valhalla/ ]

>> Basically, everything is an object, using @Value in front of a class or a record
>> transforms it to a value class, a class with no identity
>> (== compares the fields, synchronized throws an IllegalMonitorStateException,
>> new WeakRef<>(...) throws an IdentityException).
>> Adding @ZeroDefault means that the default value of the value class which is not
>> null is all fields filled with zero.

>> @NonNull allows to declare a non-null type (there is also @Nullable which is the
>> default if there is no null aware annotation).
>> For parameters, like Kotlin, sending null to a parameter of a method annotated
>> with @NonNull throws a NPE.
>> For a field a zero-default annotated with @NonNull ask for flattening, trying to
>> store null also throws a NPE.
>> For a field which is not a zero-default, even if declared @NonNull, the runtime
>> will *not* throw a NPE because the field is null before reaching its
>> initialization assignment in the constructor (and a constructor can call any
>> methods).

>> From the VM POV, a Q-type never appears inside a method descriptor. It appears
>> inside field descriptor but putfield, getfield and withfield allows a field
>> declared as a Q-type to be accessed as a L-type (this is currently simulated
>> for getfield and putfield with an invokedynamic). This is very similar to the
>> way the VM deals with arrays. And the VM knows if a parameter is a Q-type or
>> not despite the fact that only L-type appears in the method descriptor because
>> the Q-type are declared in the Preload table of the class.

>> It means that if a class/record is not accessed directly by a constructor but by
>> some static factories (like Optional) then moving in between an identity type,
>> a value type (with zero-default or not) are backward compatible changes.

>> regards,
>> Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-dev/attachments/20230111/e738a8ed/attachment.htm>


More information about the valhalla-dev mailing list