Re: JEP update: Value Objects

2021-12-21 Thread Dan Smith
> On Dec 20, 2021, at 10:54 AM, Brian Goetz  wrote:
> 
> 
> So the choices for VM infer seem to be:
> 
>  - Only inject IO for legacy concrete classes, based on classfile version, 
> otherwise require everything to be explicit;
>  - Inject IO for concrete classes when ACC_VALUE is not present, require VO 
> to be explicit;
>  - Inject IO for concrete classes when ACC_VALUE is not present; inject VO 
> for concrete classes when ACC_VALUE is present
> 

One more dimension to this is whether "inject" and "require" are talking about 
an element in the `interfaces` array of the declaration, or simply the presence 
of the interface via some combination of inheritance/declaration.

The latter seems more natural. But in "require" cases, it leads to surprising 
binary incompatibilities (per some comments I made earlier in the thread):

1) declare `interface Foo extends ValueObject` and `value class Bar extends Foo`

2) compile; javac excludes ValueObject from Bar's `interfaces`

3) Modify Foo, removing `extends ValueObject` (turns out I was overly eager 
when I put in that constraint, and I actually wouldn't mind subclasses that are 
identity classes)

4) recompile Foo separately, which succeeds

5) Try running, and discover that class Bar refuses to load, with an error 
saying it doesn't implement ValueObject ("of course it does!" you say—"it's a 
value class")

Inference is nice in that it will happily paper over these sorts of separate 
compilation mismatches.

Re: [External] : Re: Do we even need IO/VO interfaces? (was: JEP update: Value Objects)

2021-12-20 Thread forax
> From: "Brian Goetz" 
> To: "Remi Forax" 
> Cc: "daniel smith" , "Dan Heidinga"
> , "John Rose" ,
> "valhalla-spec-experts" 
> Sent: Mardi 21 Décembre 2021 01:07:15
> Subject: Re: [External] : Re: Do we even need IO/VO interfaces? (was: JEP
> update: Value Objects)

>>> Introducing new interfaces that have no methods is clearly source- and 
>>> binary
>>> compatible, so I am not particularly compelled by "some very brittle and 
>>> badly
>>> written code might break." So far, no one has proposed any examples that 
>>> would
>>> make us reconsider that.
>> ??;
>> you are forgetting inference, this code will fail to compile
>> class A {}
>> class B {}
>> var list = List.of(new A(), new B());
>> List list2 = list:

> Good catch. There is precedent for leaving certain interfaces out of 
> inference,
> though; I suspect we will want to do this for these interfaces too.
The problem is that these interfaces are only useful if they are propagated 
along the expression flow. 
But 
- if something is typed Object or Object[], that information is lost 
- if something is typed with an interface, that information is lost (only the 
concrete classes implement those interfaces) 
- you are saying that in case of inference, they are removed from the flow too. 

It seems they are only useful on a blue moon. 

Rémi 


Re: [External] : Re: Do we even need IO/VO interfaces? (was: JEP update: Value Objects)

2021-12-20 Thread Brian Goetz





Introducing new interfaces that have no methods is clearly source-
and binary compatible, so I am not particularly compelled by "some
very brittle and badly written code might break."  So far, no one
has proposed any examples that would make us reconsider that. 



??;
you are forgetting inference, this code will fail to compile
  class A {}
  class B {}
  var list = List.of(new A(), new B());
  List list2 = list:



Good catch.  There is precedent for leaving certain interfaces out of 
inference, though; I suspect we will want to do this for these 
interfaces too.




Re: Do we even need IO/VO interfaces? (was: JEP update: Value Objects)

2021-12-20 Thread forax
> From: "Brian Goetz" 
> To: "Remi Forax" 
> Cc: "daniel smith" , "Dan Heidinga"
> , "John Rose" ,
> "valhalla-spec-experts" 
> Sent: Lundi 20 Décembre 2021 20:26:01
> Subject: Do we even need IO/VO interfaces? (was: JEP update: Value Objects)

> I thought we were wrapping this up; I'm not sure how we got back to "do we 
> even
> need these at all", but OK. Splitting off a separate (hopefully short) thread.

> These interfaces serve both a dynamic and static role. Statically, they allow 
> us
> to constrain inputs, such as:

> void runWithLock(IdentityObject lock, Runnable task)

> and similar use in generic type bounds.

> Dynamically, they allow code to check before doing something partial:

> if (x instanceof IdentityObject) { synchronized(x) { ... } }

> rather than trying and dealing with IMSE.
The static role is defeated by having a java.lang.Object, a super type for both 
IdentityObject and ValueObject. 
java.io.Serializable is useless as a type, ObjectOutputStream.writeObject() 
takes an Object not a Serializable, 
same for Arrays.sort() that takes an Object[] and not an array of Comparable, 
IdentityObject (like Serializable or Comparable) as a type can be easily lost 
because of the existence of Object. 

If the type IdentityObject can be lost, as a designer, there is little point to 
have a method that takes an IdentityObject as parameter, because it forces the 
user of the API to use a cast, trading a CCE for an IMSE. 

For the dynamic role, x.getClass().isValue() does the same thing in a more 
efficient way (apart if the VM has a special optimization for IdentityObject). 

Moreover, there are very few methods that synchronize on a user provided object 
because it makes the concurrent code hard to reason about it. 
Adding a bit in the type system to support codes that people should not write 
is not exactly a win. 

> Introducing new interfaces that have no methods is clearly source- and binary
> compatible, so I am not particularly compelled by "some very brittle and badly
> written code might break." So far, no one has proposed any examples that would
> make us reconsider that.
??; 
you are forgetting inference, this code will fail to compile 
class A {} 
class B {} 
var list = List.of(new A(), new B()); 
List list2 = list: 

> As to "value class" vs "primitive class" vs "built in primitive", I see no
> reason to add *additional* mechanisms by which to distinguish these in either
> the static or dynamic type systems; the salient difference is identity vs
> value. (Reflection will almost certainly give us means to ask questions about
> how the class was declared, though.)
Primitive (builtin or not) allows tearing, so we should introduce two 
interfaces TearableObject and NonTeareableObject, because knowing if something 
is tearable or not clearly changes the algorithm that can be used. 

> As to B3: instanceof operates on reference types, so (at least from a pure 
> spec
> / model perspective), `x instanceof T` gets answered on value instances by
> lifting to the reference type, and answering the question there. So it would
> not even be a sensible question to ask "are you a primitive value vs primitive
> reference"; subtyping is a "reference affordance", and questions about
> subtyping are answered in the reference domain.

> And to B4: the goal is to make B3 and B4 as similar as possible; there are 
> going
> to be obvious ways in which we can't do this, but this should not be relevant
> to either the static or dynamic type system.
I agree that B3 and B4 should be as similar as possible, we still need 
Class.isPrimitive() to only return true for builtin primitives to be backward 
compatible. 

Rémi 

> On 12/20/2021 2:05 PM, Remi Forax wrote:

>> Brian,
>> the last time we talked about IdentityObject and ValueObject, you said that 
>> you
>> were aware that introducing those interfaces will break some existing codes,
>> but you wanted to know if it was a lot of codes or not.

>> So i do not understand now why you want to mix IdentityObject/ValueObject 
>> with
>> the runtime behavior, it seems risky and if we need to backout the 
>> introduction
>> of those interfaces, it will more work than it should.
>> Decoupling the typing part and the runtime behavior seems a better solution.

>> Moreover, the split between IdentityObject and ValueObject makes less sense 
>> now
>> that we have 3 kinds of value objects, the identityless reference (B2), the
>> primitive (B3) and the builtin primitive (B4).
>> Why do we want these types to be seen in the type system but not by example 
>> the
>> set containing only B3 and B4 ?

>> Rémi

>>> 

Do we even need IO/VO interfaces? (was: JEP update: Value Objects)

2021-12-20 Thread Brian Goetz
I thought we were wrapping this up; I'm not sure how we got back to "do 
we even need these at all", but OK.  Splitting off a separate (hopefully 
short) thread.


These interfaces serve both a dynamic and static role. Statically, they 
allow us to constrain inputs, such as:


    void runWithLock(IdentityObject lock, Runnable task)

and similar use in generic type bounds.

Dynamically, they allow code to check before doing something partial:

    if (x instanceof IdentityObject) { synchronized(x) { ... } }

rather than trying and dealing with IMSE.

Introducing new interfaces that have no methods is clearly source- and 
binary compatible, so I am not particularly compelled by "some very 
brittle and badly written code might break."  So far, no one has 
proposed any examples that would make us reconsider that.


As to "value class" vs "primitive class" vs "built in primitive", I see 
no reason to add *additional* mechanisms by which to distinguish these 
in either the static or dynamic type systems; the salient difference is 
identity vs value. (Reflection will almost certainly give us means to 
ask questions about how the class was declared, though.)


As to B3: instanceof operates on reference types, so (at least from a 
pure spec / model perspective), `x instanceof T` gets answered on value 
instances by lifting to the reference type, and answering the question 
there.  So it would not even be a sensible question to ask "are you a 
primitive value vs primitive reference"; subtyping is a "reference 
affordance", and questions about subtyping are answered in the reference 
domain.


And to B4: the goal is to make B3 and B4 as similar as possible; there 
are going to be obvious ways in which we can't do this, but this should 
not be relevant to either the static or dynamic type system.




On 12/20/2021 2:05 PM, Remi Forax wrote:

Brian,
the last time we talked about IdentityObject and ValueObject, you said 
that you were aware that introducing those interfaces will break some 
existing codes,

but you wanted to know if it was a lot of codes or not.

So i do not understand now why you want to mix 
IdentityObject/ValueObject with the runtime behavior, it seems risky 
and if we need to backout the introduction of those interfaces, it 
will more work than it should.
Decoupling the typing part and the runtime behavior seems a better 
solution.


Moreover, the split between IdentityObject and ValueObject makes less 
sense now that we have 3 kinds of value objects, the identityless 
reference (B2), the primitive (B3) and the builtin primitive (B4).
Why do we want these types to be seen in the type system but not by 
example the set containing only B3 and B4 ?


Rémi



*From: *"Brian Goetz" 
*To: *"daniel smith" , "Dan Heidinga"

*Cc: *"John Rose" ,
"valhalla-spec-experts" 
*Sent: *Lundi 20 Décembre 2021 18:54:01
*Subject: *Re: JEP update: Value Objects

I was working on some docs and am not sure if we came to a
conclusion on the rules about who may, may not, or must declare
ValueObject or IdentityObject.

Let me see if I can chart the boundaries of the design space. 
I'll start with IdentityObject since it is more constrained.

 - Clearly for legacy classes, the VM is going to have to infer
and inject IdentityObject.
 - Since IdentityObject is an interface, it is inherited; if my
super implements IO, so am I.
 - It seems desirable that a user be *allowed* to name
IdentityObject as a superinterface of an interface or abstract
class, which constrains what subclasses can do.  (Alternately we
could spell this "value interface" or "value abstract class"; this
is a separate set of tradeoffs.)
 - There is value in having exactly one way to say certain things;
it reduces the space of what has to be specified and tested.
 - I believe our goal is to know everything we need to know at
class load time, and not to have to go back and do complex checks
on a supertype when a subclass is loaded.

The choice space seems to be
  user { must, may, may not } specify IO on concrete classes
  x compiler { must, may, may not } specify IO when ACC_VALUE present
  x VM (and reflection) { mops up }

where "mopping up" minimally includes dealing with legacy classfiles.

Asking the user to say "IdentityObject" on each identity class
seems ridiculous, so we can drop that one.

  user { may, may not } specify IO on concrete classes
  x compiler { must, may, may not } specify IO when ACC_VALUE present
  x VM (and reflection) { mops up }

From a user model perspective, it seems arbitrary to say the user
may not explicitly say IO for concrete classes, but ma

Re: JEP update: Value Objects

2021-12-20 Thread Remi Forax
Brian, 
the last time we talked about IdentityObject and ValueObject, you said that you 
were aware that introducing those interfaces will break some existing codes, 
but you wanted to know if it was a lot of codes or not. 

So i do not understand now why you want to mix IdentityObject/ValueObject with 
the runtime behavior, it seems risky and if we need to backout the introduction 
of those interfaces, it will more work than it should. 
Decoupling the typing part and the runtime behavior seems a better solution. 

Moreover, the split between IdentityObject and ValueObject makes less sense now 
that we have 3 kinds of value objects, the identityless reference (B2), the 
primitive (B3) and the builtin primitive (B4). 
Why do we want these types to be seen in the type system but not by example the 
set containing only B3 and B4 ? 

Rémi 

> From: "Brian Goetz" 
> To: "daniel smith" , "Dan Heidinga"
> 
> Cc: "John Rose" , "valhalla-spec-experts"
> 
> Sent: Lundi 20 Décembre 2021 18:54:01
> Subject: Re: JEP update: Value Objects

> I was working on some docs and am not sure if we came to a conclusion on the
> rules about who may, may not, or must declare ValueObject or IdentityObject.

> Let me see if I can chart the boundaries of the design space. I'll start with
> IdentityObject since it is more constrained.

> - Clearly for legacy classes, the VM is going to have to infer and inject
> IdentityObject.
> - Since IdentityObject is an interface, it is inherited; if my super 
> implements
> IO, so am I.
> - It seems desirable that a user be *allowed* to name IdentityObject as a
> superinterface of an interface or abstract class, which constrains what
> subclasses can do. (Alternately we could spell this "value interface" or 
> "value
> abstract class"; this is a separate set of tradeoffs.)
> - There is value in having exactly one way to say certain things; it reduces 
> the
> space of what has to be specified and tested.
> - I believe our goal is to know everything we need to know at class load time,
> and not to have to go back and do complex checks on a supertype when a 
> subclass
> is loaded.

> The choice space seems to be
> user { must, may, may not } specify IO on concrete classes
> x compiler { must, may, may not } specify IO when ACC_VALUE present
> x VM (and reflection) { mops up }

> where "mopping up" minimally includes dealing with legacy classfiles.

> Asking the user to say "IdentityObject" on each identity class seems 
> ridiculous,
> so we can drop that one.

> user { may, may not } specify IO on concrete classes
> x compiler { must, may, may not } specify IO when ACC_VALUE present
> x VM (and reflection) { mops up }

> From a user model perspective, it seems arbitrary to say the user may not
> explicitly say IO for concrete classes, but may so do for abstract classes. So
> the two consistent user choices are either:

> - User can say "implements IO" anywhere they like
> - User cannot say "implements IO" anywhere, and instead we have an "identity"
> modifier which is optional on concrete classes and acts as a constraint on
> abstract classes/interfaces.

> While having an "identity" modifier is nice from a completeness perspective, 
> the
> fact that it is probably erased to "implements IdentityObject" creates
> complication for reflection (and another asymmetry between reflection and
> javax.lang.model). So it seems that just letting users say "implements
> IdentityObject" is reasonable.

> Given that the user has a choice, there is little value in "compiler may not
> inject", so the choice for the compiler here is "must" vs "may" inject. Which
> is really asking whether we want to draw the VM line at legacy vs new
> classfiles, or merely adding IO as a default when nothing else has been
> selected. Note that asking the compiler to inject based on ACC_VALUE is also
> asking pretty much everything that touches bytecode to do this too, and likely
> to generate more errors from bytecode manglers. The VM is doing inference
> either way, what we get to choose here is the axis.

> Let's put a pin in IO and come back to VO.

> The user is already saying "value", and we're stuck with the default being
> "identity". Unless we want to have the user say "value interface" for a
> value-only interface (which moves some complexity into reflection, but is also
> a consistent model), I think we're stuck with letting the user specify either
> IO/VO on an abstract class / interface, which sort of drags us towards letting
> the user say it (redundantly) on concrete classes too.

> The compiler and VM will 

Re: JEP update: Value Objects

2021-12-20 Thread Brian Goetz
I was working on some docs and am not sure if we came to a conclusion on 
the rules about who may, may not, or must declare ValueObject or 
IdentityObject.


Let me see if I can chart the boundaries of the design space. I'll start 
with IdentityObject since it is more constrained.


 - Clearly for legacy classes, the VM is going to have to infer and 
inject IdentityObject.
 - Since IdentityObject is an interface, it is inherited; if my super 
implements IO, so am I.
 - It seems desirable that a user be *allowed* to name IdentityObject 
as a superinterface of an interface or abstract class, which constrains 
what subclasses can do.  (Alternately we could spell this "value 
interface" or "value abstract class"; this is a separate set of tradeoffs.)
 - There is value in having exactly one way to say certain things; it 
reduces the space of what has to be specified and tested.
 - I believe our goal is to know everything we need to know at class 
load time, and not to have to go back and do complex checks on a 
supertype when a subclass is loaded.


The choice space seems to be
  user { must, may, may not } specify IO on concrete classes
  x compiler { must, may, may not } specify IO when ACC_VALUE present
  x VM (and reflection) { mops up }

where "mopping up" minimally includes dealing with legacy classfiles.

Asking the user to say "IdentityObject" on each identity class seems 
ridiculous, so we can drop that one.


  user { may, may not } specify IO on concrete classes
  x compiler { must, may, may not } specify IO when ACC_VALUE present
  x VM (and reflection) { mops up }

From a user model perspective, it seems arbitrary to say the user may 
not explicitly say IO for concrete classes, but may so do for abstract 
classes.  So the two consistent user choices are either:


 - User can say "implements IO" anywhere they like
 - User cannot say "implements IO" anywhere, and instead we have an 
"identity" modifier which is optional on concrete classes and acts as a 
constraint on abstract classes/interfaces.


While having an "identity" modifier is nice from a completeness 
perspective, the fact that it is probably erased to "implements 
IdentityObject" creates complication for reflection (and another 
asymmetry between reflection and javax.lang.model).  So it seems that 
just letting users say "implements IdentityObject" is reasonable.


Given that the user has a choice, there is little value in "compiler may 
not inject", so the choice for the compiler here is "must" vs "may" 
inject.  Which is really asking whether we want to draw the VM line at 
legacy vs new classfiles, or merely adding IO as a default when nothing 
else has been selected. Note that asking the compiler to inject based on 
ACC_VALUE is also asking pretty much everything that touches bytecode to 
do this too, and likely to generate more errors from bytecode manglers.  
The VM is doing inference either way, what we get to choose here is the 
axis.


Let's put a pin in IO and come back to VO.

The user is already saying "value", and we're stuck with the default 
being "identity".  Unless we want to have the user say "value interface" 
for a value-only interface (which moves some complexity into reflection, 
but is also a consistent model), I think we're stuck with letting the 
user specify either IO/VO on an abstract class / interface, which sort 
of drags us towards letting the user say it (redundantly) on concrete 
classes too.


The compiler and VM will always type-check the consistency of the value 
keyword/bit and the implements clause.  So the real question is where 
the inference/injection happens.  And the VM will have to do injection 
for at least IO at least for legacy classes.


So the choices for VM infer seem to be:

 - Only inject IO for legacy concrete classes, based on classfile 
version, otherwise require everything to be explicit;
 - Inject IO for concrete classes when ACC_VALUE is not present, 
require VO to be explicit;
 - Inject IO for concrete classes when ACC_VALUE is not present; inject 
VO for concrete classes when ACC_VALUE is present


Is infer measurably more costly than just ordinary classfile 
checking?  It seems to me that if all things are equal, the simpler 
injection rule is preferable (the third), mostly on the basis of what it 
asks of humans who write code to manipulate bytecode, but if there's a 
real cost to the injection, then having the compiler help out is 
reasonable. (But in that case, it probably makes sense for the compiler 
to help out in all cases, not just VO.)




On 12/2/2021 6:11 PM, Dan Smith wrote:

On Dec 2, 2021, at 1:04 PM, Dan Heidinga  wrote:

On Thu, Dec 2, 2021 at 10:05 AM Dan Smith  wrote:

On Dec 2, 2021, at 7:08 AM, Dan Heidinga  wrote:

When converting back from our internal form to a classfile for the
JVMTI RetransformClasses agents, I need to either filter the interface
out if we injected it or not if it was already there.  JVMTI's
GetImplementedInterfaces call has a similar 

Re: JEP update: Value Objects

2021-12-02 Thread Dan Smith
> On Dec 2, 2021, at 1:04 PM, Dan Heidinga  wrote:
> 
> On Thu, Dec 2, 2021 at 10:05 AM Dan Smith  wrote:
>> 
>> On Dec 2, 2021, at 7:08 AM, Dan Heidinga  wrote:
>> 
>> When converting back from our internal form to a classfile for the
>> JVMTI RetransformClasses agents, I need to either filter the interface
>> out if we injected it or not if it was already there.  JVMTI's
>> GetImplementedInterfaces call has a similar issue with being
>> consistent - and that's really the same issue as reflection.
>> 
>> There's a lot of small places that can easily become inconsistent -
>> and therefore a lot of places that need to be checked - to hide
>> injected interfaces.  The easiest solution to that is to avoid
>> injecting interfaces in cases where javac can do it for us so the VM
>> has a consistent view.
>> 
>> 
>> I think you may be envisioning extra complexity that isn't needed here. The 
>> plan of record is that we *won't* hide injected interfaces.
> 
> +1.  I'm 100% on board with this approach.  It cleans up a lot of the
> potential corner cases.
> 
>> Our hope is that the implicit/explicit distinction is meaningless—that 
>> turning implicit into explicit via JVMTI would be a 100% equivalent change. 
>> I don't know JVMTI well, so I'm not sure if there's some reason to think 
>> that wouldn't be acceptable...
> 
> JVMTI's "GetImplementedInterfaces" spec will need some adaptation as
> it currently states "Return the direct super-interfaces of this class.
> For a class, this function returns the interfaces declared in its
> implements clause."
> 
> The ClassFileLoadHook (CFLH) runs either with the original bytecodes
> as passed to the VM (the first time) or with "morally equivalent"
> bytecodes recreated by the VM from its internal classfile formats.
> The first time through the process the agent may see a value class
> that doesn't have the VO interface directly listed while after a call
> to {retransform,redefine}Classes, the VO interface may be directly
> listed.  The same issues apply to the IO interface with legacy
> classfiles so with some minor spec updates, we can paper over that.
> 
> Those are the only two places: GetImplementedInterfaces & CFLH and
> related redefine/retransform functions, I can find in the JVMTI spec
> that would be affected.  Some minor spec updates should be able to
> address both to ensure an inconsistency in the observed behaviour is
> treated as valid.

Useful details, thanks.

Would it be a problem if the ClassFileLoadHook gives different answers 
depending on the timing of the request (derived from original bytecodes vs. 
JVM-internal data)? If we need consistent answers, it may be that the "original 
bytecode" approach needs to reproduce the JVM's inference logic. If it's okay 
for the answers to change, there's less work to do.

To highlight your last point: we *will* need to work this out for inferred 
IdentityObject, whether we decide to infer ValueObject or not.

Re: JEP update: Value Objects

2021-12-02 Thread Dan Heidinga
On Thu, Dec 2, 2021 at 10:05 AM Dan Smith  wrote:
>
> On Dec 2, 2021, at 7:08 AM, Dan Heidinga  wrote:
>
> When converting back from our internal form to a classfile for the
> JVMTI RetransformClasses agents, I need to either filter the interface
> out if we injected it or not if it was already there.  JVMTI's
> GetImplementedInterfaces call has a similar issue with being
> consistent - and that's really the same issue as reflection.
>
> There's a lot of small places that can easily become inconsistent -
> and therefore a lot of places that need to be checked - to hide
> injected interfaces.  The easiest solution to that is to avoid
> injecting interfaces in cases where javac can do it for us so the VM
> has a consistent view.
>
>
> I think you may be envisioning extra complexity that isn't needed here. The 
> plan of record is that we *won't* hide injected interfaces.

+1.  I'm 100% on board with this approach.  It cleans up a lot of the
potential corner cases.

> Our hope is that the implicit/explicit distinction is meaningless—that 
> turning implicit into explicit via JVMTI would be a 100% equivalent change. I 
> don't know JVMTI well, so I'm not sure if there's some reason to think that 
> wouldn't be acceptable...

JVMTI's "GetImplementedInterfaces" spec will need some adaptation as
it currently states "Return the direct super-interfaces of this class.
For a class, this function returns the interfaces declared in its
implements clause."

The ClassFileLoadHook (CFLH) runs either with the original bytecodes
as passed to the VM (the first time) or with "morally equivalent"
bytecodes recreated by the VM from its internal classfile formats.
The first time through the process the agent may see a value class
that doesn't have the VO interface directly listed while after a call
to {retransform,redefine}Classes, the VO interface may be directly
listed.  The same issues apply to the IO interface with legacy
classfiles so with some minor spec updates, we can paper over that.

Those are the only two places: GetImplementedInterfaces & CFLH and
related redefine/retransform functions, I can find in the JVMTI spec
that would be affected.  Some minor spec updates should be able to
address both to ensure an inconsistency in the observed behaviour is
treated as valid.

--Dan



Re: JEP update: Value Objects

2021-12-02 Thread Dan Smith
On Dec 2, 2021, at 7:08 AM, Dan Heidinga 
mailto:heidi...@redhat.com>> wrote:

When converting back from our internal form to a classfile for the
JVMTI RetransformClasses agents, I need to either filter the interface
out if we injected it or not if it was already there.  JVMTI's
GetImplementedInterfaces call has a similar issue with being
consistent - and that's really the same issue as reflection.

There's a lot of small places that can easily become inconsistent -
and therefore a lot of places that need to be checked - to hide
injected interfaces.  The easiest solution to that is to avoid
injecting interfaces in cases where javac can do it for us so the VM
has a consistent view.

I think you may be envisioning extra complexity that isn't needed here. The 
plan of record is that we *won't* hide injected interfaces. Our hope is that 
the implicit/explicit distinction is meaningless—that turning implicit into 
explicit via JVMTI would be a 100% equivalent change. I don't know JVMTI well, 
so I'm not sure if there's some reason to think that wouldn't be acceptable...


Re: [External] : Re: JEP update: Value Objects

2021-12-02 Thread Dan Heidinga
Replying to both this and the previous email in one:

> I guess I prefer C and D over A and B because of the reflection magic problem,
> and also because of Dan H’s issue (IIUC) about “where do we look for the
> metadata, if not in somebody’s constant pool?”

+1 I prefer C or D as well for similar reasons.

> Since D and C have about equal practical effect, and D is both simpler to
> specify and less ceremony, I prefer D best of all.
>
> I agree that ACC_VALUE is useful to prevent “action at a distance”.
>
> There is the converse problem that comes from the redundancy:
> What happens if the class directly implements or inherits ValueObject
> and ACC_VALUE is not set?  I guess that is an error also.

That's the unfortunate part of having two ways to say things and why I
really liked Brian's suggestion to only have the interface.  The VM
can infer the bit from the presence of the interface, especially if we
went with option C as the interface would always be directly present
in the value classfiles.  It's a little different than the normal path
of "as long as it's in the hierarchy" but it does mean there's only 1
piece of info.

> I hit send too soon:  That’s probably true for concrete classes.
> For abstracts, ACC_VALUE must not be set (yes?) and ValueObject
> “just flows” along with all the other super types, with no particular
> notice.  It all comes together when ACC_VALUE appears, and that
> must be on a final, concrete class.

That's a reasonable restriction if we keep the bit - ACC_VALUE is only
for concrete classes and must be met by either a direct or inherited
VO interface.

> I keep wondering what ACC_VALUE “should mean” for an abstract.
> Maybe it “should mean” that the abstract is thereby also forced to
> implement VO, so that all subtypes will be VO’s.

Isn't that the role of the VO interface though?  I think it makes more
sense to keep ACC_VALUE for final concrete classes.

>
> The slightly different meaning of ACC_PERMITS_VALUE is “hold
> off on injecting IdentityObject at this point”.  Because the type
> might allow subtypes that implement VO (whether abstract or
> concrete).  At this point it also allows IdentityObject to be
> introduced in subtypes.  Mmm… It could also have been
> spelled ACC_NOT_NECESSARILY_IDENTITY.

Or ACC_UNDECIDED.  If we see bucket 2 classes becoming popular enough
that the ACC_PERMITS_VALUE is a common flag on abstract classes, we
may want to pick a name that indicates "both allowed".  It's our
current code base's bias towards identity that makes us want to spell
it "PERMITS_VALUE" when, as John says, flipping the meaning is equally
valid.

>
> As we said in the meeting, it seems to need magic injection of
> IdObj, even if we can require non-magic explicit presence of VO.
> Dan H., will the metadata pointer of IdObj be a problem to access,
> if it is magically injected?

I'm not concerned about the metadata pointer - injecting an extra
interface is doable and required for legacy identity classes.  My
worry is consistency flowing through the system - primarily with
determining whether an interface is injected or not.  At least in our
implementation, the easiest way to inject the interface is to add it
when converting the .class file into our internal forms (ROM & RAM
class).  Once injected, it looks like any other interface.

When converting back from our internal form to a classfile for the
JVMTI RetransformClasses agents, I need to either filter the interface
out if we injected it or not if it was already there.  JVMTI's
GetImplementedInterfaces call has a similar issue with being
consistent - and that's really the same issue as reflection.

There's a lot of small places that can easily become inconsistent -
and therefore a lot of places that need to be checked - to hide
injected interfaces.  The easiest solution to that is to avoid
injecting interfaces in cases where javac can do it for us so the VM
has a consistent view.

None of this is impossible - or even that hard - but it's really easy
to get wrong and only discover after it's been in the wild for a
while.  When the bug reports come in, we'll have to decide which set
of users to break - those who wanted it returned like a normal
interface or those who expected it to be hidden.

My vote is for javac to inject the VO interface as before we ship is
the only time we can by design avoid a long tail of (minor) bugs.

--Dan



Re: [External] : Re: JEP update: Value Objects

2021-12-01 Thread Remi Forax
> From: "John Rose" 
> To: "daniel smith" 
> Cc: "Dan Heidinga" , "valhalla-spec-experts"
> 
> Sent: Jeudi 2 Décembre 2021 00:56:02
> Subject: Re: [External] : Re: JEP update: Value Objects

> On Dec 1, 2021, at 3:29 PM, Dan Smith < [ mailto:daniel.sm...@oracle.com |
> daniel.sm...@oracle.com ] > wrote:

>> So we went down the path of "maybe there's no need for a flag at all" in 
>> today's
>> meeting, and it might be worth more consideration, but I convinced myself 
>> that
>> the ACC_VALUE flag serves a useful purpose for validation and clarifying 
>> intent
>> that can't be reproduced by a "directly/indirectly extends ValueObject" test.

>> As you suggest, though, we could mandate that ACC_VALUE implies 'implements
>> ValueObject’.

> Assuming ACC_VALUE is part of the design, there are actually four
> things we can specify, for the case when a class file has ACC_VALUE set:

> A. Inject ValueObject as a direct interface, whether or not it was already
> inherited.
> B. Inject ValueObject as a direct interface, if it is not already inherited.
> C. Require ValueObject to be present as a direct interface, whether or not it
> was already inherited.
> D. Require ValueObject to be present as an interface, either direct or
> inherited.

> A and B will look magic to reflection.
> B is slightly more parsimonious and less predictable than A.
> C and D are less magic to reflection, and require a bit more “ceremony” in the
> class file.
> D is less ceremony than C.
> Also, the D condition is a normal subtype condition, while the C condition is
> unusual to the JVM.

> I guess I prefer C and D over A and B because of the reflection magic problem,
> and also because of Dan H’s issue (IIUC) about “where do we look for the
> metadata, if not in somebody’s constant pool?”

> Since D and C have about equal practical effect, and D is both simpler to
> specify and less ceremony, I prefer D best of all.

> I agree that ACC_VALUE is useful to prevent “action at a distance”.

> There is the converse problem that comes from the redundancy:
> What happens if the class directly implements or inherits ValueObject
> and ACC_VALUE is not set? I guess that is an error also.

As Daniel said during the meeting and in a following email, from the POV of 
javac, the compiler should add "implements ValueObject" on all concrete value 
classes even if ValueObject is already present in the hierarchy to avoid action 
at distance (to detect when a super type change from implementing ValueObject 
to implement IdentityObject by example). With that requirement, for the VM, D 
and C are equivalent for all classes generated by javac. 

So D is Ok. 

Rémi 

> — John


Re: JEP update: Value Objects

2021-12-01 Thread Dan Smith
> On Dec 1, 2021, at 4:56 PM, John Rose  wrote:
> 
> On Dec 1, 2021, at 3:29 PM, Dan Smith  wrote:
>> 
>> So we went down the path of "maybe there's no need for a flag at all" in 
>> today's meeting, and it might be worth more consideration, but I convinced 
>> myself that the ACC_VALUE flag serves a useful purpose for validation and 
>> clarifying intent that can't be reproduced by a "directly/indirectly extends 
>> ValueObject" test.
>> 
>> As you suggest, though, we could mandate that ACC_VALUE implies 'implements 
>> ValueObject’.
> 
> Assuming ACC_VALUE is part of the design, there are actually four
> things we can specify, for the case when a class file has ACC_VALUE set:
> 
> A. Inject ValueObject as a direct interface, whether or not it was already 
> inherited.
> B. Inject ValueObject as a direct interface, if  it is not already inherited.
> C. Require ValueObject to be present as a direct interface, whether or not it 
> was already inherited.
> D. Require ValueObject to be present as an interface, either direct or 
> inherited.

I realize my last sentence there is ambiguous, so thanks for spelling these 
out. I meant that Dan has suggested (D), and we could consider doing so. (The 
JEP says do either A or B, it's vague about what "considered to implement" 
means.)

> A and B will look magic to reflection.

This I'm unclear on. What's the magic? Are you imagining that certain 
superinterfaces be suppressed by reflection. As I said, our intent is to *not* 
suppress anything.

> B is slightly more parsimonious and less predictable than A.

Yeah, I'm not sure what I prefer. The distinction only matters, I think, for 
reflection.

> C and D are less magic to reflection, and require a bit more “ceremony” in 
> the class file.
> D is less ceremony than C.
> Also, the D condition is a normal subtype condition, while the C condition is 
> unusual to the JVM.

The "normal subtype condition" is a big reason to prefer D over C.

> I guess I prefer C and D over A and B because of the reflection magic problem,
> and also because of Dan H’s issue (IIUC) about “where do we look for the
> metadata, if not in somebody’s constant pool?”

I'll reiterate this point:

>> the trouble with gating off less-preferred behavior in old versions is that 
>> it's still there and still must be supported. JVMs end up with two 
>> strategies instead of one. A (great strategy+ok strategy) combination is 
>> arguably *worse* than just (ok strategy) everywhere.


We haven't really eliminated these problems if we're still inferring 
IdentityObject elsewhere. We've just (slightly) reduced their footprint. At the 
expense of living with two strategies instead of one.

> Since D and C have about equal practical effect, and D is both simpler to
> specify and less ceremony, I prefer D best of all.

I'm concerned about D's separate compilation problem: implementing ValueObject 
at compile time doesn't guarantee implementing ValueObject at runtime. That 
change is not, strictly speaking, a binary compatible change, but a 
superinterface author might think they could get away with it, and the 
resulting error message seems excessively punitive: "you can't load this class 
because some superinterface changed its mind about allowing identity class 
implementations". They wanted to allow more, and ended up allowing less.

Which means, to be safe, the compiler should always redundantly implement 
ValueObject in value classes, but then a compiler might forget to do so and 
introduce a subtle bug, ...

Tolerable, but it's a rough edge of D.



Re: JEP update: Value Objects

2021-12-01 Thread Dan Smith
> On Dec 1, 2021, at 9:32 AM, Remi Forax  wrote:
> 
> Hi Daniel,
> this is really nice.
> 
> Here are my remarks.
> 
> "It generally requires that an object's data be located at a fixed memory 
> location"
> remove "fixed", all OpenJDK GCs move objects.
> Again later, remove "fixed" in "That is, a value object does not have a fixed 
> memory address ...".

Yeah, was hoping I could weasel my way out of that with "generally", but okay. 
Changed to "particular memory location".

> At the beginning of the section "Value class declarations", before the 
> example, i think we also need a sentence saying that fields are implicitly 
> final.

Eh, this is putting more detail in the introductory paragraph than I want. I 
think I'm happier going the other direction—putting the rules about 'final' and 
'abstract' class modifiers in the "subject to the following restrictions" list 
after the example. Then the intro is just two sentences about the 'value' 
keyword.

> Class file and representation, about ACC_PERMITS_VALUE, what's the difference 
> between "permits" and "allow" in English ?

Very close synonyms, I'd say? I would use them interchangeably.

The reason I chose "permits" is because we already have a PermittedSubclasses 
attribute that serves a similar purpose.

> In section "Java language compilation",
> "Each class file generated by javac includes a Preload attribute naming any 
> value class that appears in one of the class file's field or method 
> descriptors."
> + if a value class is the receiver of a method call/field access (the 
> receiver is not part of the method descriptor in the bytecode).

The need here is to identity inlinable classes at the declaration site. Use 
sites don't need it. (And the the type of 'this' at the declaration site is, of 
course, already loaded.)

> In section "Performance model"
> "... must ensure that fields and arrays storing value objects are updated 
> atomically.",
> not only stores, loads has to be done atomically too.

"read and written atomically", then.

> The part "Initially, developers can expect the following from the HotSpot 
> JVM" is dangerous because it will be read as Hotspot will do that forever.
> We have to be more vague here, "a Java VM may ..."

Yes, message received. I'll ask around about the best way to document our 
intentions for the targeted release (perhaps outside the JEP) without 
suggesting a constraint on the abstract feature.



Re: [External] : Re: JEP update: Value Objects

2021-12-01 Thread John Rose
On Dec 1, 2021, at 3:56 PM, John Rose 
mailto:john.r.r...@oracle.com>> wrote:

There is the converse problem that comes from the redundancy:
What happens if the class directly implements or inherits ValueObject
and ACC_VALUE is not set?  I guess that is an error also.

I hit send too soon:  That’s probably true for concrete classes.
For abstracts, ACC_VALUE must not be set (yes?) and ValueObject
“just flows” along with all the other super types, with no particular
notice.  It all comes together when ACC_VALUE appears, and that
must be on a final, concrete class.

I keep wondering what ACC_VALUE “should mean” for an abstract.
Maybe it “should mean” that the abstract is thereby also forced to
implement VO, so that all subtypes will be VO’s.

The slightly different meaning of ACC_PERMITS_VALUE is “hold
off on injecting IdentityObject at this point”.  Because the type
might allow subtypes that implement VO (whether abstract or
concrete).  At this point it also allows IdentityObject to be
introduced in subtypes.  Mmm… It could also have been
spelled ACC_NOT_NECESSARILY_IDENTITY.

As we said in the meeting, it seems to need magic injection of
IdObj, even if we can require non-magic explicit presence of VO.
Dan H., will the metadata pointer of IdObj be a problem to access,
if it is magically injected?


Re: [External] : Re: JEP update: Value Objects

2021-12-01 Thread John Rose
On Dec 1, 2021, at 3:29 PM, Dan Smith 
mailto:daniel.sm...@oracle.com>> wrote:

So we went down the path of "maybe there's no need for a flag at all" in 
today's meeting, and it might be worth more consideration, but I convinced 
myself that the ACC_VALUE flag serves a useful purpose for validation and 
clarifying intent that can't be reproduced by a "directly/indirectly extends 
ValueObject" test.

As you suggest, though, we could mandate that ACC_VALUE implies 'implements 
ValueObject’.

Assuming ACC_VALUE is part of the design, there are actually four
things we can specify, for the case when a class file has ACC_VALUE set:

A. Inject ValueObject as a direct interface, whether or not it was already 
inherited.
B. Inject ValueObject as a direct interface, if  it is not already inherited.
C. Require ValueObject to be present as a direct interface, whether or not it 
was already inherited.
D. Require ValueObject to be present as an interface, either direct or 
inherited.

A and B will look magic to reflection.
B is slightly more parsimonious and less predictable than A.
C and D are less magic to reflection, and require a bit more “ceremony” in the 
class file.
D is less ceremony than C.
Also, the D condition is a normal subtype condition, while the C condition is 
unusual to the JVM.

I guess I prefer C and D over A and B because of the reflection magic problem,
and also because of Dan H’s issue (IIUC) about “where do we look for the
metadata, if not in somebody’s constant pool?”

Since D and C have about equal practical effect, and D is both simpler to
specify and less ceremony, I prefer D best of all.

I agree that ACC_VALUE is useful to prevent “action at a distance”.

There is the converse problem that comes from the redundancy:
What happens if the class directly implements or inherits ValueObject
and ACC_VALUE is not set?  I guess that is an error also.

— John



Re: [External] : Re: JEP update: Value Objects

2021-12-01 Thread Dan Smith

> On Dec 1, 2021, at 8:48 AM, Dan Heidinga  wrote:
> 
>> class file representation & interpretation
>> 
>> A value class is declared in a class file using the ACC_VALUE modifier 
>> (0x0100). At class load time, the class is considered to implement the 
>> interface ValueObject; an error occurs if a value class is not final, has a 
>> non-final instance field, or implements—directly or 
>> indirectly—IdentityObject.
> 
> I'll reiterate my earlier pleas to have javac explicitly make them
> implement ValueObject.  The VM can then check that they have both the
> bit and the interface.

So we went down the path of "maybe there's no need for a flag at all" in 
today's meeting, and it might be worth more consideration, but I convinced 
myself that the ACC_VALUE flag serves a useful purpose for validation and 
clarifying intent that can't be reproduced by a "directly/indirectly extends 
ValueObject" test.

As you suggest, though, we could mandate that ACC_VALUE implies 'implements 
ValueObject'. Some reasons not to require this:

- 'implements ValueObject' may be redundant if an ancestor implements 
ValueObject; but leaving it off risks a separate compilation error (e.g., 
ancestor used to implement ValueObject, doesn't anymore). So I think the proper 
compilation strategy would be to always implement it directly, even 
redundantly. There's an opportunity for a subtle compiler bug.

- It's extra ceremony in the class file. 

- Inferring is consistent with what we do for at least some identity classes. 
Inferring everywhere is, in some ways, simpler.*

(*Tangent about the idea of inferring IdentityObject in old versions, but 
requiring IdentityObject in new versions: the trouble with gating off 
less-preferred behavior in old versions is that it's still there and still must 
be supported. JVMs end up with two strategies instead of one. A (great 
strategy+ok strategy) combination is arguably *worse* than just (ok strategy) 
everywhere.)

> It's a simpler model if the interface is
> always there for values as the VM won't have to track whether it was
> injected for a value class or explicitly declared.  Why does that
> matter?  For two reasons: JVMTI will need to be consistent in the
> classfile bytes it returns and not included the interface if it was
> injected (less tracking), and given earlier conversations about
> whether to "hide" the injected interface from Class::getInterfaces,
> always having it for values removes one more sharp edge.

The plan of record is to make no distinction between inferred and explicit 
superinterfaces in reflection. Is that not acceptable for JVMTI? If there's no 
need for a distinction, does that address your concern about inferred supers?

Re: JEP update: Value Objects

2021-12-01 Thread Remi Forax
Hi Daniel,
this is really nice.

Here are my remarks.

"It generally requires that an object's data be located at a fixed memory 
location"
remove "fixed", all OpenJDK GCs move objects.
Again later, remove "fixed" in "That is, a value object does not have a fixed 
memory address ...".

At the beginning of the section "Value class declarations", before the example, 
i think we also need a sentence saying that fields are implicitly final.

Class file and representation, about ACC_PERMITS_VALUE, what's the difference 
between "permits" and "allow" in English ?

In section "Java language compilation",
"Each class file generated by javac includes a Preload attribute naming any 
value class that appears in one of the class file's field or method 
descriptors."
+ if a value class is the receiver of a method call/field access (the receiver 
is not part of the method descriptor in the bytecode).

In section "Performance model"
"... must ensure that fields and arrays storing value objects are updated 
atomically.",
not only stores, loads has to be done atomically too.

The part "Initially, developers can expect the following from the HotSpot JVM" 
is dangerous because it will be read as Hotspot will do that forever.
We have to be more vague here, "a Java VM may ..."

regards,
Rémi

- Original Message -
> From: "daniel smith" 
> To: "valhalla-spec-experts" 
> Sent: Mardi 30 Novembre 2021 01:09:06
> Subject: JEP update: Value Objects

> I've been exploring possible terminology for "Bucket 2" classes, the ones that
> lack identity but require reference type semantics.
> 
> Proposal: *value classes*, instances of which are *value objects*
> 
> The term "value" is meant to suggest an entity that doesn't rely on mutation,
> uniqueness of instances, or other features that come with identity. A value
> object with certain field values is the same (per ==), now and always, as 
> every
> "other" value object with those field values.
> 
> (A value object is *not* necessarily immutable all the way down, because its
> fields can refer to identity objects. If programmers want clean immutable
> semantics, they shouldn't write code (like 'equals') that depends on these
> identity objects' mutable state. But I think the "value" term is still
> reasonable.)
> 
> This feels like it may be an intuitive way to talk about identity without
> resorting to something verbose and negative like "non-identity".
> 
> If you've been following along all this time, there's potential for 
> confusion: a
> "value class" has little to do with a "primitive value type", as we've used 
> the
> term in JEP 401. We're thinking the latter can just become "primitive type",
> leading to the following two-axis interpretation of the Valhalla features:
> 
> -
> Value class reference type (B2 & B3.ref)  | Identity class type (B1)
> -
> Value class primitive type (B3)   |
> -
> 
> Columns: value class vs. identity class. Rows: reference type vs. primitive
> type. (Avoid "value type", which may not mean what you think it means.)
> 
> Fortunately, the renaming exercise is just a problem for those of us who have
> been closely involved in the project. Everybody else will approach this grid
> with fresh eyes.
> 
> (Another old term that I am still finding useful, perhaps in a slightly
> different way: "inline", describing any JVM implementation strategy that
> encodes value objects directly as a sequence of field values.)
> 
> Here's a new JEP draft that incorporates this terminology and sets us up to
> deliver Bucket 2 classes, potentially as a separate feature from Bucket 3:
> 
> https://bugs.openjdk.java.net/browse/JDK-8277163
> 
> Much of JEP 401 ends up here; a revised JEP 401 would just talk about 
> primitive
> classes and types as a special kind of of value class.


Re: JEP update: Value Objects

2021-12-01 Thread Dan Heidinga
>
> Here's a new JEP draft that incorporates this terminology and sets us up to 
> deliver Bucket 2 classes, potentially as a separate feature from Bucket 3:
>
> https://bugs.openjdk.java.net/browse/JDK-8277163
>
> Much of JEP 401 ends up here; a revised JEP 401 would just talk about 
> primitive classes and types as a special kind of of value class.
>

Reading through this I see that ACC_VALUE classes implicitly implement
ValueObject:
> class file representation & interpretation
>
> A value class is declared in a class file using the ACC_VALUE modifier 
> (0x0100). At class load time, the class is considered to implement the 
> interface ValueObject; an error occurs if a value class is not final, has a 
> non-final instance field, or implements—directly or indirectly—IdentityObject.

I'll reiterate my earlier pleas to have javac explicitly make them
implement ValueObject.  The VM can then check that they have both the
bit and the interface.  It's a simpler model if the interface is
always there for values as the VM won't have to track whether it was
injected for a value class or explicitly declared.  Why does that
matter?  For two reasons: JVMTI will need to be consistent in the
classfile bytes it returns and not included the interface if it was
injected (less tracking), and given earlier conversations about
whether to "hide" the injected interface from Class::getInterfaces,
always having it for values removes one more sharp edge.

--Dan



Re: JEP update: Value Objects

2021-11-30 Thread Dan Smith
On Nov 30, 2021, at 12:05 AM, John Rose 
mailto:john.r.r...@oracle.com>> wrote:

Also, I’m not really demanding a title change here, Dan, but rather asking
everyone to be careful about any presupposition that “of course we will
heal the rift by making all primitives be classes”.  Or even “all primitives
be objects.”  Those are easy ideas to fall into by accident, and I don’t want
us to get needlessly muddled about them as we sort them out.

+1

I've been defaulting in descriptions like my two-axis grid to the plan of 
record, until we settle on a revised plan. But quite possible that "class" is 
not the right word for the second row.

(As for JEP 401—it will need to be revised to build on the Value Objects JEP. 
What you're seeing right now is unchanged from a few months ago. An updated 
iteration to come...)



Re: JEP update: Value Objects

2021-11-29 Thread John Rose
P.S. I’d like to emphasize that none of my pleas for caution apply to the
JEP draft titled Value Objects.

That very nice JEP draft merely links to the JEP draft titled Primitive Classes,
which is the JEP with the potential problem I’m taking pains to point out here.

Also, I’m not really demanding a title change here, Dan, but rather asking
everyone to be careful about any presupposition that “of course we will
heal the rift by making all primitives be classes”.  Or even “all primitives
be objects.”  Those are easy ideas to fall into by accident, and I don’t want
us to get needlessly muddled about them as we sort them out.

(Having picked Value as the winner for the first JEP, replacing Primitive
Objects with Primitive Values in the second JEP is not exactly graceful,
is it?  Naming is hard.  If you were to change the title I suggest simply
“Primitives” as the working title, until we figure out exactly what we
want these Primitives to be, relative to other concepts.  Just a suggestion.)

On Nov 29, 2021, at 10:53 PM, John Rose 
mailto:john.r.r...@oracle.com>> wrote:

Two points from me for the record:

1. I re-read the JEP draft now titled Value Objects, and liked everything I 
saw, including the new/old term “Value” replacing “Pure” and “Inline”.

2. In your mail, and in the companion JEP draft titled Primitive Objects, you 
refer to “primitive classes” and their objects.  It would make our 
deliberations simpler, IMO, if we were to title this less prescriptively as 
“Primitives” or “Primitive Types” or “Primitive Types and Values”, rather than 
“Primitive Classes”…



Re: JEP update: Value Objects

2021-11-29 Thread John Rose
Two points from me for the record:

1. I re-read the JEP draft now titled Value Objects, and liked everything I 
saw, including the new/old term “Value” replacing “Pure” and “Inline”.

2. In your mail, and in the companion JEP draft titled Primitive Objects, you 
refer to “primitive classes” and their objects.  It would make our 
deliberations simpler, IMO, if we were to title this less prescriptively as 
“Primitives” or “Primitive Types” or “Primitive Types and Values”, rather than 
“Primitive Classes”, because (a) there’s no logical need for the new things to 
be classes, and (b) it might actually be helpful for them *not* to be, in the 
end, after deliberation.  Putting the word “classes” in the title presupposes 
an answer to deliberations that have not yet been concluded.

People should note that the term “class” and “object” is only loosely bound to 
the term “primitive” in most of our designs, since (of course) today no 
primitives at all are either defined by classes or have objects.  They have 
corresponding reference or box classes and objects, to be precise.  Today a 
primitive type “has a class” but it is not the case that it “is a class”.  We 
could choose to preserve this state of affairs instead of fixing it by making 
“classes everywhere”; it makes some dependent choices easier to make.  As you 
know, one possible bridge to the future is, “Today all types are a disjoint 
union of primitives, classes, and interfaces, and tomorrow the same will be 
true, with all three possessing class-like declarations.”

What about objects, shouldn’t primitives at least be objects?  Well, interfaces 
don’t directly have objects today; they have objects of implementing classes.  
Likewise, primitives need never have objects directly, as long as they have 
objects which properly relate to them—their boxes.  Boxes-boxes-everywhere 
certainly has its downsides, include pedagogical downsides, but that doesn’t 
make it a non-starter.

Instead, if we choose to use the terms “primitive class” and “primitive object” 
as exact counterparts to “reference class” and “reference object”, as your 
chart suggests, Dan, we will have to account for the duplication and/or ad hoc 
division of various attributions of classes and objects between the “primitive  
class” and its corresponding “reference class” (e.g., int.ref, Point.ref).  I 
think a good leading question is, “if a primitive is a class, and its reference 
type is also a class, which of its methods are situated on the primitive class, 
and which are situated on the reference class?”  I would suggest that we be 
more sure we want to have two classes per primitive, or only-a-primitive-class 
per primitive, before we presuppose a decision by putting the word “Classes” in 
the title of JEP 402.

> On Nov 29, 2021, at 4:09 PM, Dan Smith  wrote:
> 
> I've been exploring possible terminology for "Bucket 2" classes, the ones 
> that lack identity but require reference type semantics.
> 
> Proposal: *value classes*, instances of which are *value objects*
> 
> The term "value" is meant to suggest an entity that doesn't rely on mutation, 
> uniqueness of instances, or other features that come with identity. A value 
> object with certain field values is the same (per ==), now and always, as 
> every "other" value object with those field values.
> 
> (A value object is *not* necessarily immutable all the way down, because its 
> fields can refer to identity objects. If programmers want clean immutable 
> semantics, they shouldn't write code (like 'equals') that depends on these 
> identity objects' mutable state. But I think the "value" term is still 
> reasonable.)
> 
> This feels like it may be an intuitive way to talk about identity without 
> resorting to something verbose and negative like "non-identity".
> 
> If you've been following along all this time, there's potential for 
> confusion: a "value class" has little to do with a "primitive value type", as 
> we've used the term in JEP 401. We're thinking the latter can just become 
> "primitive type", leading to the following two-axis interpretation of the 
> Valhalla features:
> 
> -
> Value class reference type (B2 & B3.ref)  | Identity class type (B1)
> -
> Value class primitive type (B3)   |
> -
> 
> Columns: value class vs. identity class. Rows: reference type vs. primitive 
> type. (Avoid "value type", which may not mean what you think it means.)
> 
> Fortunately, the renaming exercise is just a problem for those of us who have 
> been closely involved in the project. Everybody else will approach this grid 
> with fresh eyes.
> 
> (Another old term that I am still finding useful, perhaps in a slightly 
> different way: 

JEP update: Value Objects

2021-11-29 Thread Dan Smith
I've been exploring possible terminology for "Bucket 2" classes, the ones that 
lack identity but require reference type semantics.

Proposal: *value classes*, instances of which are *value objects*

The term "value" is meant to suggest an entity that doesn't rely on mutation, 
uniqueness of instances, or other features that come with identity. A value 
object with certain field values is the same (per ==), now and always, as every 
"other" value object with those field values.

(A value object is *not* necessarily immutable all the way down, because its 
fields can refer to identity objects. If programmers want clean immutable 
semantics, they shouldn't write code (like 'equals') that depends on these 
identity objects' mutable state. But I think the "value" term is still 
reasonable.)

This feels like it may be an intuitive way to talk about identity without 
resorting to something verbose and negative like "non-identity".

If you've been following along all this time, there's potential for confusion: 
a "value class" has little to do with a "primitive value type", as we've used 
the term in JEP 401. We're thinking the latter can just become "primitive 
type", leading to the following two-axis interpretation of the Valhalla 
features:

-
Value class reference type (B2 & B3.ref)| Identity class type (B1)
-
Value class primitive type (B3) |
-

Columns: value class vs. identity class. Rows: reference type vs. primitive 
type. (Avoid "value type", which may not mean what you think it means.)

Fortunately, the renaming exercise is just a problem for those of us who have 
been closely involved in the project. Everybody else will approach this grid 
with fresh eyes.

(Another old term that I am still finding useful, perhaps in a slightly 
different way: "inline", describing any JVM implementation strategy that 
encodes value objects directly as a sequence of field values.)

Here's a new JEP draft that incorporates this terminology and sets us up to 
deliver Bucket 2 classes, potentially as a separate feature from Bucket 3:

https://bugs.openjdk.java.net/browse/JDK-8277163

Much of JEP 401 ends up here; a revised JEP 401 would just talk about primitive 
classes and types as a special kind of of value class.