Re: JEP update: Value Objects
> 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)
> 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)
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)
> 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)
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
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
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
> 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
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
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
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
> 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
> 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
> 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
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
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
> 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
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
> > 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
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
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
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
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.