I summarized some recent Project Valhalla LW2 "inline types" progress that was made public recently in my blog post "Valhalla LW2 Progress - Inline Types." In this post, I illustrate some of the concepts summarized in that post with code examples executed against recently released Valhalla Early Access Build jdk-14-valhalla+1-8 (2019/7/4). All code examples featured in this post are available on GitHub.
The OpenJDK Wiki page "LW2" provides an illustrative example of inline types via source code for a class called "InlineType
." My example makes some minor adaptions and additions to this class and is available on GitHub as a class called InlineTypeExample
. Some items that stand out immediately when reviewing this source code are the presence of the keyword inline
and the presence of the ?
in the Comparable
's generic parameter.
The source code for my adapted InlineTypeExample
class has an attempt to have the inline type class extend
another class commented out because that leads to a compiler error: error: Inline type may not extend another inline type or class
Similarly, that source code also has the method that attempts to set the integer field of the inline type class commented out because that will also not compile: error: cannot assign a value to final variable
With the current Valhalla LW2 build, I'm allowed to make my inline type class Serializable and it still compiles successfully.
Another GitHub-hosted illustrative class is Lw2Demonstration
that compares and contrasts characteristics of the inline type class (and instances of it) to the JDK-provided java.lang.Integer class (and its instances) and to a simple custom-built Integer
wrapper (and its instances). This demonstration class calls reflective methods (some which are new to the JDK 14-based Valhalla build) on the "class" types of all three things (inline type, Integer
, and custom Integer
wrapper) and calls some "common" methods [toString(), equals(Object), hashCode()] on instances of all three types.
Two methods are commented out in the class Lw2Demonstration
because they each attempt to perform functionality on the inline type that is not supported for inline types. One of these methods attempts to synchronize on a variable of the inline type. When attempting to compile this synchronization of an inline type, the following compiler error message is seen: error: unexpected type ... required: reference ... found: InlineTypeExample
Another attempts to assign an inline type to null
. When attempting to compile this, the following error message is encountered: error: incompatible types: <null> cannot be converted to InlineTypeExample
The following method from Lw2Demonstration
writes out several metadata characteristics of the class types.
/** * Provides metadata extracted from the provided instance of * {@link Class} as a single {@link String}. * * @param classToInvokeInlineMethodsOn Class for which metadata * is to be extracted and returned in {@link String} format; * should NOT be {@code null}. * @return Single string representation of metadata extracted * from the provided {@link Class} instance. * @throws NullPointerException Thrown if {@code null} is * provided for my sole parameter. */ public static String extractClassMetadata(final Class classToInvokeInlineMethodsOn) { Objects.requireNonNull("Provided Class must be non-null to extract its metadata."); final String className = classToInvokeInlineMethodsOn.getSimpleName(); final String outputPrefix = "\n" + className + ".class."; return outputPrefix + "getName(): " + classToInvokeInlineMethodsOn.getName() + outputPrefix + "getSimpleName(): " + classToInvokeInlineMethodsOn.getSimpleName() + outputPrefix + "getCanonicalName(): " + classToInvokeInlineMethodsOn.getCanonicalName() + outputPrefix + "toGenericString(): " + classToInvokeInlineMethodsOn.toGenericString() + outputPrefix + "getTypeName(): " + classToInvokeInlineMethodsOn.getTypeName() + outputPrefix + "getComponentType(): " + classToInvokeInlineMethodsOn.getComponentType() + outputPrefix + "isInlineClass(): " + classToInvokeInlineMethodsOn.isInlineClass() + outputPrefix + "isIndirectType(): " + classToInvokeInlineMethodsOn.isIndirectType() + outputPrefix + "isNullableType(): " + classToInvokeInlineMethodsOn.isNullableType() + outputPrefix + "isPrimitive(): " + classToInvokeInlineMethodsOn.isPrimitive() + outputPrefix + " final?: " + isFinal(classToInvokeInlineMethodsOn); }
Some of the methods invoked on the Class
instance in the previous method are new to the JDK 14-based Valhalla LW2 early access build. These include isInlineClass()
, isIndirectType()
, and isNullableType()
.
The main demonstration class Lw2Demonstration
creates instances of the inline type class InlineTypeExample
, of JDK-provided java.lang.Integer
, and of a custom wrapper for an Integer
. The demonstration then runs instances of these three classes and the class definitions through the same methods and writes out the results for each so that they can be compared and contrasted. Here is the output from running this example against the Valhalla Early Access Build mentioned at the beginning of this post.
InlineTypeExample.class.getName(): dustin.examples.valhalla.lw2.InlineTypeExample InlineTypeExample.class.getSimpleName(): InlineTypeExample InlineTypeExample.class.getCanonicalName(): dustin.examples.valhalla.lw2.InlineTypeExample InlineTypeExample.class.toGenericString(): public final inline class dustin.examples.valhalla.lw2.InlineTypeExample InlineTypeExample.class.getTypeName(): dustin.examples.valhalla.lw2.InlineTypeExample InlineTypeExample.class.getComponentType(): null InlineTypeExample.class.isInlineClass(): true InlineTypeExample.class.isIndirectType(): false InlineTypeExample.class.isNullableType(): false InlineTypeExample.class.isPrimitive(): false InlineTypeExample.class. final?: true InlineTypeExample: toString(): [dustin.examples.valhalla.lw2.InlineTypeExample someIntegerValue=1] InlineTypeExample: hashCode(): 1303372796 Inline Type Example ==: true Integer.class.getName(): java.lang.Integer Integer.class.getSimpleName(): Integer Integer.class.getCanonicalName(): java.lang.Integer Integer.class.toGenericString(): public final class java.lang.Integer Integer.class.getTypeName(): java.lang.Integer Integer.class.getComponentType(): null Integer.class.isInlineClass(): false Integer.class.isIndirectType(): true Integer.class.isNullableType(): true Integer.class.isPrimitive(): false Integer.class. final?: true Integer: toString(): 1 Integer: hashCode(): 1 Integer Type Example ==: false IntegerWrapper.class.getName(): dustin.examples.valhalla.lw2.IntegerWrapper IntegerWrapper.class.getSimpleName(): IntegerWrapper IntegerWrapper.class.getCanonicalName(): dustin.examples.valhalla.lw2.IntegerWrapper IntegerWrapper.class.toGenericString(): public class dustin.examples.valhalla.lw2.IntegerWrapper IntegerWrapper.class.getTypeName(): dustin.examples.valhalla.lw2.IntegerWrapper IntegerWrapper.class.getComponentType(): null IntegerWrapper.class.isInlineClass(): false IntegerWrapper.class.isIndirectType(): true IntegerWrapper.class.isNullableType(): true IntegerWrapper.class.isPrimitive(): false IntegerWrapper.class. final?: false IntegerWrapper: toString(): dustin.examples.valhalla.lw2.IntegerWrapper@5442a311 IntegerWrapper: hashCode(): 1413653265 Integer Wrapper Example ==: false
The output shown above demonstrates some of the advertised characteristics of the inline type. The most interesting are the focus of the following table.
Characteristic | Inline Type Wrapping Integer | java.lang.Integer | Custom Integer Wrapper |
---|---|---|---|
Inline? | true | false | false |
Indirect? | false | true | true |
Nullable? | false | true | true |
Final? | true | true | false |
== Valid for Equality? | true | false | false |
toString() | Implicitly Customized | Explicitly Customized | Uses Object's |
hashCode() | Implicitly Customized | Explicitly Customized | Uses Object's |
To compile and execute these examples, I needed to provide the Java compiler and launcher with some special arguments. Specifically, I compiled with --enable-preview
, -Xlint:preview
, and -source 14
. For executing the demonstration, I passed the flag --enable-preview
to the Java launcher.
The updated Valhalla Early Access Build [Build jdk-14-valhalla+1-8 (2019/7/4)] provides a convenient pre-built binary for Java developers interested in trying out Valhalla LW2 prototype inline types. This post has demonstrated some of these current LW2 inline types concepts using this build. RĂ©mi Forax has provided many more examples on GitHub (forax/valuetype-lworld).
1 comment:
Valhalla Early Access Build 14-valhalla+4-55 (2019/8/30) is now available at https://jdk.java.net/valhalla/.
Post a Comment