Saturday, August 4, 2018

Project Valhalla: A First Look at L-World Value Types

In the post "JVM Language Summit 2018 and Valhalla EA Build 0", I mentioned that Project Valhalla's "L-World Value Types" Early-Access Builds are now available for Linux/x64, macOS/x64, and Windows/x64. Specifically, "Build 0 (2018/7/30)" is available for download as a "convenience." In that same post, I also mentioned that the JVM Language Summit 2018 had just wrapped up and I provided a link to one of that event's presentations: "LWorld: the next steps on the journey to Valhalla". In this post, I use code based on the Project Valhalla "L-World Value Types" Early-Access Build 0 to illustrate some of the points made in the JVM Language Summit 2018 presentation on early versions of L-World.

CAUTION: The build discussed in this post is "intended for expert users interested in Project Valhalla", is NOT intended for production, and has severe limitations and disclaimers associated with it. This build is primarily intended for those who want to "play" with L-World value types and not for other more general uses. In announcing this build on the valhalla-dev OpenJDK mailing list, David Simms described this Build 0 as follows:

"The first truly usable value type prototype" with experimental language support. Based on JDK mainline, almost complete JDK 11. This is build "0", there are bugs, performance issues, and usability issues.

The following code listing (including the __ByValue) compiles against the L-World Value Types Early Access Build 0:

package dustin.examples.valhalla;

public final __ByValue class DoubleComplex
{
   public final double real;
   public final double imaginary;
   public DoubleComplex(final double newReal, final double newImaginary)
   {
      this.real = newReal;
      this.imaginary = newImaginary;
   }
}

The L-World Value Types Early Access Build 0 javac compiler adds some methods to the DoubleComplex class shown above beyond those added by the compiler in other versions of Java. These are perhaps most easily identified by running javap against the generated class.

As the above screen snapshot demonstrates, javap tells us that several methods were added to the DoubleComplex.class class file generated from the DoubleComplex.java source file by the L-World Value Types Early Access Build 0 javac compiler:

Compiled from "DoubleComplex.java"
public final value class dustin.examples.valhalla.DoubleComplex {
  public final double real;
  public final double imaginary;
  public dustin.examples.valhalla.DoubleComplex(double, double);
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public final java.lang.String toString();
  public final long longHashCode();
  public static dustin.examples.valhalla.DoubleComplex $makeValue$(double, double);
}

Normally, we'd only expect the javap output of a .class file generated from the .java file shown above to include the two fields and the constructor that are present in the source Java file. However, the L-World Value Types Early Access Build 0 javac compiler generated a .class file with a hashCode() implementation, an equals(Object) implementation, a toString() implementation, a longHashCode() implementation (that returns long instead of the int returned by standard hashCode()), and a mysterious-looking static method $makeValue$ because of the __ByValue reference in the source code. I wasn't able to get __MakeValue to work for me in creating an instance of this value type, but I will demonstrate the other added methods in this generated class file.

I will show some output of these methods generated on value type DoubleComplex that were not explicitly specified in the Java source code file. For these output examples, the following three instances of the DoubleComplex will be used:

private final static DoubleComplex complex1
   = new DoubleComplex(15.0, 25.0);
private final static DoubleComplex complex2
   = new DoubleComplex(25.0, 35.0);
private final static DoubleComplex complex3
   = new DoubleComplex(25.0, 35.0);

The second and third instances (complex2 and complex3) have the same values and the complex1 instance has different values. Based on these instances, the methods added to ComplexDemo by the L-World Value Types EA Build 0 javac compiler generate results that look like the following:

Examples of Methods Added to Value Type)
Method Added to Value Type Results for Instances of DoubleComplex Value Type
(methods' output in bold
toString() [value class dustin.examples.valhalla.DoubleComplex, 15.0, 25.0]
[value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]
[value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]
equals(Object) Comparing [value class dustin.examples.valhalla.DoubleComplex, 15.0, 25.0] to [value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]: false
Comparing [value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0] to [value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]: true
hashCode() Complex1.hashCode(): -478263309
Complex2.hashCode(): -455358477
Complex3.hashCode(): -455358477
longHashCode() Complex1.longHashCode(): 1610134472691
Complex2.longHashCode(): 1610157377523
Complex3.longHashCode(): 1610157377523

The table above demonstrates that reasonable implementations of toString(), equals(Object), and hashCode() are provided by default for Java value types compiled with the L-World Value Types Early Access Build 0.

To run code that used my value type, I needed to use the flag -XX:+EnableValhalla in addition to specifying the JVM flag --enable-preview. If I failed to supply the -XX:+EnableValhalla flag to the L-World Value Types Early Access Build 0 java launcher, I was presented with the error message

Exception in thread "main" java.lang.ClassFormatError: Class modifier ACC_VALUE in class dustin/examples/valhalla/DoubleComplex requires option -XX:+EnableValhalla

Things You Cannot Do with Value Types in L-World Value Types EA Build 0

There are some interesting things you cannot do with the value types created with L-World Value Types Early Access Build 0 (several of these are intentional and likely to not be changed):

  • Compare two value types with ==
    • Compile-time error: "error: value types do not support =="
  • Pass value type to System.identityHashCode(Object)
    • Compile-time error: "error: value types do not support identityHashCode"
  • Synchronize on a value type
    • Compile-time error:
      error: unexpected type
           synchronized (complex1)
           ^
             required: reference
             found:    DoubleComplex
  • Value Type cannot extend another class
    • Compile-time error: "error: value type may not extend another value or class"

Class.isValue()

Although I don't demonstrate it here, there is a method available on the java.lang.Class class with this L-World Value Types Early Access Build 0 that indicates whether the class is a value type class or not. The method, Class.isValue(), returns true if the class is a value type class or false if it is NOT a value type class.

The isValue() method also appears to throw InternalErrors if it is called upon a class that is internally labeled a value type but whose Modifiers indicate it is also an interface, an abstract class, or extends a class other than Object. This implies, of course, that a value type class cannot be declared abstract ("error: illegal combination of modifiers: abstract and final" or "error: illegal combination of modifiers: abstract and value") or be an interface ("error: illegal combination of modifiers: interface and value").

L-World's Future

Although significant progress has been made in Project Valhalla related to Value Types, there is still much work to come. The JVM Language Summit presentation I cited earlier ends with discussion about "L-World major milestones" in the slides titled "L-World Roadmap." These slides and the speakers discuss major milestones "LW1", "LW10", and "LW100" and the features and characteristics expected for each of these major milestones. There will, of course, be milestones between those numbers as well. The availability of L-World Value Types Early Access Build 0 provides a convenient mechanism for interested parties to start playing with L-World value types.

6 comments:

Unknown said...

Nice, just found your blog and posts are really up-to-date with the JDK and interesting! Good job.
Do you think value types will be out for JDK 12?

@DustinMarx said...

Hello Edoardo,

Although much work has been put into value types, they still have a long way to go, so I think it's highly unlikely we'll see them in JDK 12.

Dustin

@DustinMarx said...

Doug Lea has posted "Value type sorting" in which he discusses applying various sorting algorithms to value types and provides links to examples based on the Valhalla L-World Early Access Build 0 referenced in my blog post.

kitovsky said...

Is the case class construction suitable as a replacement for the final __ByValue class syntax?

@DustinMarx said...

See Uberto Barbini's post "A Taste of Value Types" for a detailed look at how to download and apply the Valhalla Early Access Build.

@DustinMarx said...

A new Valhalla Early Access Build [Build jdk-14-valhalla+1-8 (2019/7/4)] is available for the LW2 prototype ("inline classes"). I have posted on Valhalla LW2 inline types and using this new early access build in the posts "Valhalla LW2 Progress - Inline Types" and "Project Valhalla: A First Look at LW2 Inline Types".