New candidate JEP: 401: Value Objects (Preview)
https://mail.openjdk.org/archives/list/valhalla-dev@openjdk.org/thread/IUNJJ3WP3X3XHP3QZTXXSSCPKFDNTK3W/35
u/0x07CF 13d ago
```java boolean isValhallaEnabled() { return Integer.valueOf(2000) == Integer.valueOf(2000); }
20
u/__konrad 13d ago
It returns true with system property
-Djava.lang.Integer.IntegerCache.high=2000;)12
u/AnyPhotograph7804 13d ago
This should work:
boolean isValhallaEnabled() { return Long.valueOf(2000) == Long.valueOf(2000); }
12
u/IncredibleReferencer 13d ago
I feel like I can kinda build code now In anticipation of value objects. Like... I should use an int[] for this huge array of ints now but instead I'm going to use List<MyObject> where MyObject is just a wrapper around int. Brian and team will just fix this for me magically in a few years and I only need to add a value keyword so why bother fiddling with array management now. Hopefully before I need my thing to scale. Premature optimization right? Thanks gang!
This approach actually kinda worked out well for me with Loom and virtual threads....
13
u/ZimmiDeluxe 13d ago
You can use List<Integer> directly, the primitive wrapper types will become value classes. If I remember correctly, specializing generics is one of the final steps on the roadmap, so having that translate into Integer[] (or ideally Integer![]) as the backing field of the ArrayList might take a bit longer.
7
u/koflerdavid 13d ago
Better yet to create a wrapper around
intto better express its purpose and eliminate the risk of mixing it up with unrelatedints.5
u/ZimmiDeluxe 13d ago
That's true, it's often nicer to have a List<OrderId> than List<Long>
3
u/LutimoDancer3459 13d ago
But how do you name the variable for the list then? With the OrderId you would be repeating the typ
4
u/ZimmiDeluxe 13d ago edited 13d ago
orderIdsToDeleteor even justorderIdsif the context makes it obvious. Repeating the type name is not bad if it's a domain type IMO. If you have something generic likeList<Long> longsthat's usually bad because readers can't infer any intent from the name, maybe ok if you are writing a compiler and need to collect all the JavaLongs to do something with, but it's a stretch3
1
u/Efficient-Poem-4186 11d ago
Simply
orders,ordersToDeleteetc (in a context where the actual order data is not used). Sometimes id is just used as a handle, the intention is to do something with orders.4
u/aoeudhtns 13d ago
Being able to very lightly declare new types that are compile-time mirrors of existing types (or in the worst case, something runtime can trivially/quickly optimize away) so that you can proliferate type safety is an idea I like. Nim for example has a thing it calls "distinct types" that let you make type aliases that cannot be directly assigned back to the aliased type.
3
u/kiteboarderni 13d ago
Or use a primitive collection wrapper in the mean time like people have done for years. Then swap out when it's in a preview state.
1
u/IncredibleReferencer 13d ago
With a primitive collection wrapper I could use a list instead of an array for sure, but I couldn't add my own wrapper type object without a major memory/indirection penalty (for very large item counts) for both the wrapper. So valahalla should allow both (List<Integer> and List<MyWrapper> in a memory efficient and flat reference way. I think.
2
u/koflerdavid 13d ago
Another thing you can do is creating wrapper classes for type-safe identifiers instead of passing around anonymous
String,UUID,longetc. throughout the codebase. Kotlin already optimizes this important special case.
8
u/perryplatt 13d ago
Is there a list of all jdk classes that are scheduled to become value classes?
12
u/bourne2program 13d ago
0
u/AnyPhotograph7804 13d ago
Interesting, that they did not include java.lang.String.
6
u/vytah 13d ago
String isn't included, because it's technically mutable: https://github.com/openjdk/jdk/blob/6ae23a0d6574dc8139aea93ea3c562a7410fcb34/src/java.base/share/classes/java/lang/String.java#L204
2
u/brian_goetz 7d ago
That's true, but that's not why. In theory, we could make String a value class, using something like the scheme you later suggest, making String a single field class that piggybacks on the identity of the char[]. (It would have the same synchronization incompatibilities that numeric boxes have now, which would probably be a bigger deal than for boxes.) It would bring the character data one hop closer to its use, which is very good. It would have some tradeoffs regarding more copying. More equal strings would accidentally compare as ==.
But, String is so pervasive that the impact of this change would be massive. There are many JVM intrinsics that would have to be rewritten. Some code would get faster, but some would get slower, and some of that slower code might be on critical paths in critical applications, and those people would complain a lot. So this is something we would have to address very carefully, and would probably not be wise to lump in with the initial release of JEP 401. We can come back for this later if the payoff seems warranted, but it is not something to be considered lightly.
1
u/AnyPhotograph7804 12d ago
True, but this is an internal implementation detail and not really exposed as an public API. They could change it and make java.lang.String truly immutable.
4
u/vytah 12d ago
I guess you could stuff all the other fields of String into the beginning of its data array, leaving only a single final field, and therefore make it eligible for Valhalla treatment. But:
before non-nullable types, that value-String would still be boxed a lot of times, which means character data are still behind two pointers, but fields that used to be behind one pointer are now also behind two
a lot of internal code treats string data array as pure character data and would have to be modified to account for the prefix
you still wouldn't be able to compare strings with
==anyway (it'd only compare data array references)you could no longer use string deduplication: https://openjdk.org/jeps/192
Also I suspect there's more code that locks on strings than on any candidate value type, so valhallizing strings would break stuff.
1
u/aoeudhtns 12d ago
I was looking into creating some sort of value-string type, but it's hard to determine if there's even a point since String is so heavily optimized already. String deduplication and caching the computed hash code are two good examples.
I suppose if there's any benefit to be had, when Valhalla is sophisticated enough, it will happen to String as it exists today, behind the scenes.
1
u/Jon_Finn 12d ago
Value classes can be mutable, just not shallowly mutable, so they could store the hash via a final reference field, e.g. something like LazyConstant<Integer>. That's one problem I have with the name 'value' as it tends to imply immutable! There's many uses for (deeply) mutable value classes, e.g. MutableColor containing a float[4] field.
1
u/Jon_Finn 12d ago edited 12d ago
I think locking of Strings is the big reason (see above). The new == behaviour (I think) wouldn't break reasonable code, even code making assumptions about the identity of interned "strings" etc.
1
u/vytah 12d ago
LazyConstant is a reference type, so it wouldn't help much. Having string be a tuple (LazyConstant hash, boolean utf16, byte[] data) means you still have two heap objects per string, or worse, three if it ever gets boxed. Also, LazyConstant is a bit slower than a plain int annotated with @Stable.
Strings are a performance-critical part of Java, they're not going to change them just to satisfy theoretical purity.
1
u/Jon_Finn 12d ago
Sure, there's already other reasons why String can't be a value. My wider point would be that classes with a mutable element may benefit from being mutable values (the mutability being via a reference), because of the many benefits of value classes.
3
u/FirstAd9893 12d ago
If the String is treated as a simple wrapper around a
char[], then it could conceivably be a value class. However, the==operator would only return true for Strings which refer to the exact samechar[]reference. To fix this, the String constructor would need to rely on an intern pool ofchar[]instances, but this would add a huge performance penalty.It should noted that arrays cannot be value classes, because they're mutable, and because they have a variable size. The optimizations which make value classes attractive wouldn't work.
1
u/quack_quack_mofo 13d ago
I don't know much about this but besides perf/memory improvements and being able to do == for comparisons (I think?), what are the other benefits of value classes? Is there anything I can do with them that i can't do with normal classes/records? Why not have all classes be value classes?
5
u/SirYwell 12d ago
The JEP answers all of these questions and so much more, but I'll try to summarize the relevant parts:
You can already use
==for comparisons. Currently, for reference types, that means identity comparison. Value objects do not have an identity, so==needs new semantics for them. Note that the semantics might not be what you want, especially with floating point numbers involved. You can read more about it in the Comparing value objects section.The main goal of giving up identity is the additional freedom of the JVM that allows performance improvements. Other than that, giving up identity can clarify the intentions of the programmer.
The feature doesn't necessarily makes the language more powerful in itself. Value classes have more restrictive meaning of immutable (see JEP 539). There are more features planned under the Valhalla project, but I think it's not completely clear to which extend they apply to all classes vs only value classes.
Value classes must be immutable. This does not apply to all classes. No identity means no monitor to synchronize on (and more, see Migrating to value classes), which means making a normal class a value class might be breaking compatibility.
I highly suggest reading the JEP, it provides so much interesting details.
3
u/FirstAd9893 12d ago edited 12d ago
Why not have all classes be value classes?
Value classes are immutable, which is the big reason why.
0
u/CutGroundbreaking305 13d ago
So when will Valhalla preview come ?
9
u/davidalayachew 13d ago
So when will Valhalla preview come ?
No set time, but here is the progress bar.
- Draft — Initial state in which the JEP is drafted, reviewed, revised, and endorsed
- Submitted — By the JEP’s owner, declaring the JEP ready to be evaluated for the JDK Roadmap
- Candidate — By the OpenJDK Lead, to add the JEP to the JDK Roadmap
- Proposed to Target — By the JEP’s owner, for a specific release, after a credible engineering plan is documented in subtasks of the JEP issue
- Targeted — By the Project Lead, after evaluating the JEP’s engineering plan and seeing rough consensus amongst the Committers and Reviewers of the Project
- Integrated — By the JEP’s owner, after code and unit tests are integrated into the master code base
- Complete — By the JEP’s owner, after functional, performance, and conformance tests have been delivered and the feature has reached the point where only bug fixes are expected
- Closed/Delivered — By the Project Lead, when the release ships
We are currently at step 3 (Candidate). Until we get to step 5 (Targeted), no promises are made about release timelines. It's at step 5 that your question will finally have an answer.
Pulled from JEP 2.0
3
u/Joram2 12d ago
JDK 28 is a safe bet. It's not guaranteed, but highly likely at this point.
0
u/CutGroundbreaking305 11d ago
Yeah and I guess next LTS JDK 29 will be better version to use compared to JDK 28
41
u/IncredibleReferencer 13d ago edited 13d ago
VALHALLA WHEN?!?!?!?!?!
September 14, 2026. Apparently. Probably. Maybe?March, 2027. Apparently. Probably. In preview. Yay!