JEP update: Value Objects

Dan Smith daniel.smith at oracle.com
Thu Dec 2 00:25:08 UTC 2021


> On Dec 1, 2021, at 4:56 PM, John Rose <john.r.rose at oracle.com> wrote:
> 
> On Dec 1, 2021, at 3:29 PM, Dan Smith <daniel.smith at 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.

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.



More information about the valhalla-spec-observers mailing list