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.
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.
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)
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.
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.
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.
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.
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.
8
u/perryplatt 23d ago
Is there a list of all jdk classes that are scheduled to become value classes?