Evolving the wrapper classes
Kevin Bourrillion
kevinb at google.com
Wed Jun 17 22:30:37 UTC 2020
Hmm, just maybe this will be less confusing than I was fearing. I'm seeing
now that "Integer is the real class, int is alias for Integer.val" is a
whole lot cleaner than "int becomes a val-default class and Integer is
demoted to alias for int.ref", which for some reason was the way I was
thinking of it.
On Wed, Jun 17, 2020 at 2:39 PM Dan Smith <daniel.smith at oracle.com> wrote:
Here's a concrete proposal for how we'll evolve the wrapper classes (Byte,
> Short, Integer, Long, Float, Double, Character, and Boolean) to be inline
> classes whose ".val" representations are (in the Java language) the
> primitive types.
>
> This has the effect of replacing boxing conversions in the Java language
> with lighter-weight reference conversions (no identity is imposed), and
> will facilitate specialization in the JVM by wrapping primitive values in
> lightweight inline class instances.
>
> Important concepts in this approach:
>
> - The wrapper classes are reference-default classes—'Integer' is a '.ref'
> type.
> - In the language, 'int' is an alias for 'Integer.val'. These are the same
> type.
- In the JVM, there are three distinct types: 'Ljava/lang/Integer;',
> 'Qjava/lang/Integer$val;', and 'I'
>
> The below outline feels pretty complete to me, as far as the core
> library/JVM/compiler components are concerned, and quite achievable. Please
> raise anything I'm overlooking (I'm sure there's something...).
>
> ---
>
> Step 1: Warnings
>
> In the near future, we implement a variety of warnings for clients of the
> wrapper classes who rely on features that will break when the wrapper
> classes are inline classes:
>
Cool, these would have been nice to have years ago anyway. :-) We have
several of them on for Google code already and I'll see if we can roll out
the rest to see what kinds of things blow up.
> Library changes:
> - The constructors, currently marked deprecated, are deprecated for
> removal. This should amplify warnings about their use.
>
> Java compiler changes:
> - Attempts to synchronize on or invoke wait/notify methods of expressions
> with wrapper class static types produce a new warning.
> - Possibly, uses of '==', 'identityHashCode', or 'clone' on these
> expressions produce a warning.
> - Possibly, any uses of 'getClass' that compare with '==' to wrapper class
> literals produce a warning.
>
> JVM changes:
> - Possibly, runtime warnings occur mimicking some of the compiler
> warnings, but using runtime types.
>
> (Note that all of these warnings may also apply to Value-based Classes.
> The wrapper classes happen to fall short of the value-based class
> requirements in their factories' guarantees about identity; these rules
> about factories and equality are probably unnecessary limitations, given
> the current deterministic behavior of acmp.)
>
> ---
>
> Step 2: Preview Feature
>
> When, or sometime after, we ship inline classes as a preview feature, we
> support treating the wrapper classes as inline.
>
> JVM changes (when --enable-preview is set):
> - References to java/lang/Integer and java/lang/Integer$val are hacked to
> load special class files corresponding to the .ref and .val types of inline
> class Integer.
> - The type [I is considered by the verifier to be equivalent to
> [java/lang/Integer$val. Array operations (aaload, iaload, etc.) support
> this.
>
> Java language/compiler changes (when --enable-preview is set):
> - The class file reader knows how to find the special Integer.class and
> Integer$val.class.
> - The type 'Integer.val' is equivalent to 'int'. Primitive types are
> inline types—they have members, support method invocation, etc.
>
This at least *suggests *that `42L.hashCode()` would begin to work just as
`"foo".hashCode()` does?
> - Where necessary (depending on the operations being performed), the
> compiler generates conversions between 'I' and 'java/lang/Integer$val'. 'I'
> is preferred wherever possible.
> - Boxing can be specified with stronger guarantees about '=='.
>
> ---
>
> Step 3: Standard Feature
>
> When we're ready to leave preview, we'll need to raise the profile of
> "those things we warned about are going to blow up now!".
>
> Library changes:
> - The wrapper classes are declared in source as reference-default inline
> classes.
> - The constructors are removed, replaced with private constructors.
>
> JVM changes:
> - Wrapper classes are loaded using standard processes.
>
> Java language/compiler changes:
> - The wrapper classes have special permission to declare fields of their
> own type.
>
Fair. I actually see this as rather parallel to the way the class Object in
Object.java gets to be its own superclass.
I think I'm able to make sense of this plan.
Users *can* write `Integer.val` in their code, but would there ever be a
good reason to? I assume we would always prefer `int`. And this actually
makes me wonder if it's worth considering also allowing `int.ref` to be an
alias for `Integer` because it would allow users to drop the word `Integer`
from their code more completely, and therefore `int` would look more and
more like it was just an inline type like any other. It reminds you that
the old boxing/unboxing isn't in play anymore. And `int.ref` is more
self-evidently something you can't synchronize on, etc. But, what would
remain weird is that you don't *actually *find a val-default class called
`int` sitting in an `int.java` file.
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
More information about the valhalla-spec-observers
mailing list