Fwd: Value objects with no companion reference type

Brian Goetz brian.goetz at oracle.com
Wed Sep 21 19:43:06 UTC 2022


Received on the -comments list.




-------- Forwarded Message --------
Subject: 	Value objects with no companion reference type
Date: 	Tue, 20 Sep 2022 16:17:06 -0500
From: 	Clement Cherlin <ccherlin at gmail.com>
To: 	valhalla-spec-comments at openjdk.org



Are ref-less Objects compatible with the Java language? I think the
answer may sadly be "no".

Imagine OptionalValue is an interface for Optional-like types and
Int128 is a 128-bit integer value type.

no-ref value record NoRefOptional<T>(T item) implements OptionalValue<T> { }

new OptionalValue<Int128>[] = { new NoRefOptional<>(new Int128(3)) };

What happens? An interface-typed array is necessarily an array of
references. You can't stuff a larger-than-reference-size inline value
in there without breaking the fixed-size semantics of a Java array.

Either you need a pseudo-reference which takes up the same space as a
reference and acts like a reference but isn't a reference (what is
it?), or you get an ArrayStoreException because the value doesn't fit.

This will occur any time you try to store a no-ref object in a
ref-typed-array of superclass or superinterface type, including the
omnipresent Object[].

In order to wholly avoid the Object[] problem, no-ref values could not
be cast to Object, same as primitives. No-ref values could not be cast
to interface types, same as primitives. Client code would have to
treat each one as a unique, unrelated type... same as primitives. The
only way to pass no-ref values and store them in reference contexts
would be to wrap them in heap objects, but without the possibility of
auto-boxing. In essence, to treat them as Objects, you would need to
either resort to a cumbersome generic like Optional, or manually
implement a ref-mirror like Integer.

Do we want that?

Valhalla is finally unifying primitives with objects. No-ref values
would recreate many of the sharp edges Valhalla is sanding off of
primitives. While I fully believe Java *should* have been designed
from the beginning to support user-defined non-null / no-ref objects,
it wasn't. I think it's too late to shoehorn them in without breaking
changes to the language. The bedrock assumption that you can store,
pass, or return _any_ value via an "Object" or "Object[]" typed
variable, parameter or method is too deeply ingrained into Java syntax
(Object... x) and libraries (map.get()) to fix at this late date.

While I badly want no-ref (or at least non-nullable) value types in
Java, I don't see a way to get them without either a hard fork (Python
3 style), or making them behave in all the awkward, inconvenient ways
primitives do pre-Valhalla.

I think the best we can reasonably do, given Java's pervasive
ref-ness, is non-nullable value types that can be converted into
special non-null refs which will often be inlined (lightweight
boxing). Those have challenges of their own including array
initialization, covariant arrays, and heap pollution, but I'm hopeful
those problems are solvable.

You will still run into NullPointerExceptions attempting to cast null
from Object or interface types to non-null types. That problem exists
right now when unboxing a null primitive wrapper. So while it's no
better, it's also no worse.

I do still think .ref and .val projections as distinct types with
their own .class objects and especially their own visibility mechanics
is an undesirable outcome. If there's any reasonable way to unify
them, they should be unified.

Cheers,

Clement
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-experts/attachments/20220921/93b8f0d3/attachment-0001.htm>


More information about the valhalla-spec-experts mailing list