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 <[email protected]> To: [email protected] 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
