Showing posts with label Valhalla. Show all posts
Showing posts with label Valhalla. Show all posts

Monday, September 28, 2020

Moving Toward Inline Classes: JEP 390 and the @ValueBased Annotation

Candidate JEP 390 ("Warnings for Value-Based Classes") was announced this past week by Mark Reinhold on the OpenJDK jdk-dev mailing list. This is a JDK Enhancement Proposal that may be more exciting in what it indicates (progress toward inline classes) than what it actually is (annotation and warnings about "improper attempts to synchronize on instances" of @ValueBased-annotated JDK classes that might be come inline classes).

The term "Value-based Classes" was included in the Java SE 8 Javadoc documentation, which identified the following characteristics of "instances of a value-based class" at that time:

  • "final and immutable (though may contain references to mutable objects)"
  • Implement "equals, hashCode, and toString ... solely [computed] from the instance's state and not from its identity or the state of any other object or variable"
  • Do NOT use "identity-sensitive operations such as reference equality (==) between instances, identity hash code of instances, or synchronization on an instances's intrinsic lock"
  • "Are considered equal solely based on equals()" rather than "on reference equality (==)"
  • "Instantiated through factory methods which make no committment as to the identity of returned instances" rather than providing accessible constructors
  • "Are freely substitutable when equal"

That Java SE 8 documentation also warned that "a program may produce unpredictable results if it attempts to distinguish two references to equal values of a value-based class, whether directly via reference equality or indirectly via an appeal to synchronization, identity hashing, serialization, or any other identity-sensitive mechanism." It further emphasizes, "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." This documentation remains essentially the same today (Java 15). This documentation is linked to from certain identified JDK classes' Javadoc comments. A good overview on value-based classes is available in Nicolai Parlog's blog post "Value-Based Classes."

Although some JDK classes have been identified in their Javadoc as value-based classes since Java 8, JEP 390 aims to provide the annotation @ValueBased for these types of JDK classes. The annotation is a stronger construct than a comment and is specifically intended to be used in conjunction with "warnings about improper attempts to synchronize on instances of such classes." The advantage of such an annotation is that developers can be warned about current uses in their code to synchronize on instances of classes that may one day be unsuitable for such synchronization. Because some likely significant time will pass between the availability of this warning and the actual coversion of these @ValueBased-annotated classes to inline classes (the JEP word this as, "several releases before the migration occurs"), developers will have ample opportunity to change the classes upon which they apply synchronization.

The warning about use of JDK classes for synchronization has benefit in its own right. In addition, I think this JEP is an exciting step toward inline types and the JEP is full of details about inline types. Specifically, the first paragraph of the "Motivation" section of JEP 390 states:

The Valhalla Project is pursuing a significant enhancement to the Java programming model in the form of inline classes. Such classes declare their instances to be identity-free and capable of inline or flattened representations, where instances can be copied freely between memory locations and encoded using solely the values of the instances' fields.

Perhaps the most anticipatory sentence in JEP 390 is in the second paragraph of the "Motivation" section (I've added the highlighting): "The design and implementation of inline classes is sufficiently mature that we can confidently anticipate migrating certain classes in the Java Platform to become inline classes in a future release."

The "Motivation" section of JEP 390 also enumerates the "properties" of a "candidate inline class." These are very simlar to the characteristics of "value-based classes" listed earlier:

  • "Is final"
  • "Declares only final instance fields"
  • "Extends Object, or a hierarchy of abstract classes that declare no instance fields and have no instance initialization logic"
  • "Declares only private constructors, or has deprecated its constructors for removal"
  • "Does not promise a unique instance will be created with each factory-method invocation (or any other instance creation mechanism)"
  • "Does not rely upon or expose object identity through any of its methods"
  • "Overrides toString, equals, and hashCode"
  • "Declares no synchronized methods, and discourages clients from performing synchronization"

JEP 390 also comments on the not-so-surprising closeness of the listed "properties" of "inline classes" to the characteristics of "value-based classes":

The Java Platform API uses the term value-based class to informally describe certain classes that satisfy similar constraints. If a class is described as value-based then it will probably be able to become an inline class.

JEP 390 explains that the @ValueBased annotation "will be introduced to indicate a class, interface, or method result for which no instances are expected to rely on object identity." The annotation is intended to "communicate to developers that they should exercise caution when using == or identityHashCode, and should not perform synchronization."

One of the other sections of JEP 390 that is particularly interesting to me is the section in the "Description" that lists likely "declarations in the Java Platform API and the JDK" to which the @ValueBased annotation may be applied. These include the "primitive wrapper classes" (perhaps one of the categories of most commonly used classes with synchronization that will need to be changed), the "optional classes" such as java.util.Optional, many classes in the java.time API, the java.util "collection factories", and more.

Constructs annotated with @ValueBased annotation will be highlighted in a javac warning. JEP 390 discusses how compile-time and runtime warnings will eventully become errors in some cases as @ValueBased-annotated classes become inline classes:

When a @ValueBased class becomes an inline class, the runtime warnings will be superseded by standard errors. At compile time, synchronization on an inline class type may also trigger a standard error. Compiler warnings will continue to be useful for interface types and method results.

The @ValueBased annotation and associated warnings will help developers to migrate their Java code that uses identified JDK value-based classes in a way not compatible with inline classes to safer alternatives. JEP 390 not only spells out the details of this, but also provides evidence of the growing maturity of the Project Valhalla work on inline classes.

Friday, July 10, 2020

Potential Inlined JDK Classes

Earlier this week, Dan Smith posted "JEP draft: Identity Warnings for Inline Class Candidates" on the valhalla-spec-experts mailing list. The purpose of this post was to introduce a draft JEP ("Identity Warnings for Inline Class Candidates") associated with JDK-8249100.

The main intent of this JEP is to "provide warnings at compile time and runtime for behaviors that will change when certain classes of the Java SE APIs become inline classes." Although I think it's a good idea to have these warnings to help Java developers recognize coming change and opportunities for change, I find the background details provided to in this draft JDK Enhancement Proposal to be as interesting as the end objective. This draft JEP consolidates discussions and decisions discussed among many different threads and messages on the mailing lists in a single easily referenced location.

Inline Classes in Java

The "Motivation" section of the draft JEP states that inline classes "declare their instances to be identity-free and capable of 'inline' or 'flattened' representations, where instances can be copied freely between memory locations and encoded using solely the values of the instances' fields." That same section also outlines two operations (monitoring/locking with synchronized and instantiation with new) that will not be supported by the identity-less inline classes. Because certain operations will not be allowed on inline classes and because some current JDK classes that may be used with these operations may be transitioned to inline classes at some point, it is desirable to have this draft JEP's proposed warnings. These warnings alert developers to their current uses of these inline class candidate JDK classes in conjunction with these operations that will not be supported on inline classes in the future (eventually an error will result).

For more background on inline classes, see the March 2020 version of the State of Valhalla document, in which Brian Goetz makes these observations:

  • "Inline classes are heterogeneous aggregates that explicitly disavow object identity."
  • Inline classes "must be immutable and cannot be layout-polymorphic."
  • "Inline classes have some restrictions compared to ordinary (identity) classes; they are final, their fields are final, and their ability to participate in inheritance is limited."
  • "Inline classes can use most mechanisms available to classes: methods, constructors, fields, encapsulation, type variables, annotations, etc"
  • "The slogan" for inline classes "is Codes like a class, works like an int."
  • "Inline types could equally be thought of as 'faster classes' or 'user-definable primitives'."

Identified JDK Inline Class Candidates

The "Description" section of the draft JEP lists several bullets of classes and groups of classes that are "likely to become inline classes." These candidate JDK inline classes are listed, as of this writing, as follows:

  • Primitive Wrapper Classes: java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double, java.lang.Boolean, java.lang.Character
  • Optional Classes: java.util.Optional, java.util.OptionalInt, java.util.OptionalLong, java.util.OptionalDouble
  • Java Time Classes: java.time.Instant, java.time.LocalDate, java.time.LocalTime, java.time.LocalDateTime, java.time.ZonedDateTime, java.time.ZoneId, java.time.OffsetTime, java.time.OffsetDateTime, java.time.ZoneOffset, Duration, java.time.Period, java.time.Year, java.time.YearMonth, java.time.MonthDay, and select classes in java.time.chrono package.
  • Collections Returned from Collection Factories: java.util.List.of, java.util.List.copyOf, java.util.Set.of, java.util.Set.copyOf, java.util.Map.of, java.util.Map.copyOf, java.util.Map.ofEntries, and java.util.Map.entry
  • java.lang.Runtime.Version
  • java.lang.ProcessHandles Implementations
  • java.lang.constant.ConstantDesc Implementations (except java.lang.String)
  • Select Classes in the jdk.incubator.foreign Module

JDK Classes That Will Not Be Inlined

There are some JDK-provided classes that, at first thought, might seem like candidates to be inline classes, but turn out to have characteristics that make them unlikely to ever be transitioned. These include java.lang.String and java.math.BigInteger and java.math.BigDecimal.

Conclusion

The recently proposed draft JEP discussed in this post provides a centralized location for updated background details related to the currently planned inline classes feature being discussed and worked as part of Project Valhalla. Keeping in mind that this is a draft JEP about an in-work feature, this draft JEP provides insight into how inline classes will change how we write and use Java classes.

Tuesday, February 18, 2020

Updates on Valhalla and Amber Records (Mid-February 2020)

Two posts on OpenJDK mailing lists today summarize the status of Project Valhalla and Project Amber's Records.

Valhalla

Brian Goetz begins his post "Valhalla -- finding the primitives" with this sentence, "I think its worth reflecting on how far we've come in Valhalla, both for the specific designs in the VM and language, and the clarity of the basic concepts." This post contains a brief history of the major design models that have been employed with Valhalla to this point and talks about the advantages and disadvantages of each of these models.

About "Q World," Goetz writes (I've added the emphasis), "The idea was that we would declare a class as either a value class or a 'regular' class, and we would derive various properties based on that." Goetz outlines these properties:

Q-World: Differentiating Properties of Regular Versus Value Classes
PropertyRegular ClassesValue Classes
Identity?YesNo
Nullable?YesNo
Reference types?YesNo

Goetz explains that "there were many aspects which were either confusing or unsatisfying" (he provides several examples of these) about the "Q World" approach and that the approach lacked a "clean story for migration."

Goetz describes "conflating" certain "distinctions" when working with "L World":

  • "nullable vs non-nullable"
  • "pass-by-reference vs pass-by-value / flattened"
  • "reference type vs value type"
  • "identity-ful vs identity-free"

Goetz discusses how the current state of Valhalla builds on lessons learned from the "Q World" and "L World" stages. He writes:

The primitive that Valhalla introduces into class declaration is whether the instances of the class have identity or not. Traditional classes are now revealed to be "identity classes"; the new kind (identity-free) are called "inline classes". (This might not be the final word on the subject.)

Another lesson learned in Valhalla efforts is summarized:

A big AHA of the recent iterations is that it makes sense to talk about both values of inline classes and references to those values. Reference type has (almost) nothing to do with inline vs identity -- it has to do with whether the value set of the type contains values, or references.

Based on these summarized observations, Goetz writes about the "ref/val notation for the types":

"Inline" is a way of saying "identity free" when declaring classes, but it doesn't say anything (yet) about the semantics of how we represent variables on the heap or pass them on the stack. For this, we need an additional property of the type, and ref vs val seems to ideally describe what we mean."

Amber Records

In the post "[records] Summary so far," Gavin Bierman writes about "some remaining design decisions concerning records." This post outlines the following questions/design decisions and then provides partial or complete answers to the design decisions (see the post for the additional details related to each design decision).

  1. Q1. Should the distinguished supertype of records java.lang.Record be renamed?
  2. Q2. Accessibility of mandated members.
  3. Q3. Nesting.
  4. Q4. Abstract records.
  5. Q5. Deconstruction patterns.
  6. Q6. @deprecated
  7. Q7. .equals and .toString are slow.
  8. Q8. Translation strategy.
  9. Q9. Hashing.
  10. Q10. Special annotation for explicit declaration of accessors.
  11. Q11. Changing the spec of .toString method
  12. Q12. Transactional methods
  13. Q13. Factory methods instead of constructors.

Although Records are available as a preview feature in JDK 14, it's obvious much work is still being done on them. This preview status provides an opportunity for Records to be used and tested to gain feedback that can change how they are implemented. The thirteen design decisions listed above (some of which are decidedly no change and some which are possible changes) demonstrate that Records are still going to be fine-tuned.

Thursday, January 30, 2020

Recent Valhalla News (Late January 2020)

There has been significant discussion, design, implementation, and testing related to aspects of OpenJDK Project Valhalla in recent months, but a couple things have struck me as particularly interesting over the last few days in terms of Valhalla progress. I briefly summarize those here.

 

Latest on JDK Release Associated with Valhalla

Frédéric Parain has posted "Valhalla EG 20200129" on the valhalla-spec-experts mailing list. This posting constitutes the meeting notes from the Valhalla Expert Group Meeting on 29 January 2020.

There are several interesting discussion points in these Valhalla Expert Group Meeting notes, but none may be more interesting than the answer to the question, "Is there a JDK release targeted for Valhalla?" In response to that question, the notes provide "bullets" that constitute Brian Goetz's response:

  • "too early to say"
  • "VM work is consolidating"
  • "language work still needs significant work before having a road-map"
  • "first release won't have all the features but have to have further additions in mind"

Although there's still much work required for Valhalla, I interpret these comments in a positive manner, especially when compared to responses to a similar question in months and years past.

 

The Future of Integer

The previously referenced Valhalla Expert Group Meeting Notes for 29 January 2020 include this note attributed to Brian Goetz: "Retrofitting of Integer: seemed impossible, but now seems more feasible."

I am not certain of the context of those notes, but reading these notes did make me think of Brian Goetz's discussion in the December 2019 edition of "State of Valhalla" regarding "Integer and friends." In particular, Goetz discusses migrating primitives by changing the "wrapper types (such as Integer and friends) to be interfaces" so that "these interfaces will become the reference projection for the primitives." Or, as Rafael Winterhalter articulates it, "inline class int implements Integer."

Related to this, Goetz wrote in the 6 December 2019 post "Long-awaited State of the Values docs" (I added emphasis):

The other major AHA buried in this document is the realization that the language and VM models need not align 100%. LWorld is the right VM model, but we can use it as a _translation target_ rather than our language model. This allows the primitives to blossom into full inline classes. In the new world, we have inline classes and identity classes, primitives are mostly just inline classes, and the relationship between inlines and identity classes is isomorphic to the current relationship between primitives and classes.

Goetz also discusses "migrating Integer and friends to be inline-friendly" in the post "Superclasses for inline classes."

 

Optional and Integer Will Be Interfaces Instead of Classes

The December 2019 "State of Valhalla" document explains that the Optional class of today will be changed to an interface and that the "wrapper types Integer and friends" will be migrated "to be interfaces, using the same techniques as with migrating Optional."

One downside to this conversion of Optional, Integer, and friends from classes to interfaces is that comparisons of getClass() calls in existing code against these literal types will break (because the classes implementing the interfaces will be returned in the future instead of the interface name). To deal with this, Bug JDK-8237074 ("[lworld] Compiler should emit a warning if code compares the result of getClass() against the class literal for an interface") has been written and addressed in the repo-valhalla repository. Any legacy code that compares the results of a getClass() call to a literal such as java.lang.Integer.class or java.util.Object.class may not work correctly with these changes, but at least there will be a warning.

 

New Edition of "State of Valhalla" Coming Soon?

It sounds possible that there will soon be an updated version of "State of Valhalla." In the 29 January 2020 Vallhalla EG Meeting notes, there are these notes attributed to Brian Goetz:

  • "working on reference projection as an interface or an abstract class"
  • "possible update next week, working on simplification"
  • "would lead to rewrite of 'State of Valhalla'"

 

Interfaces IdentityObject and InlineObject Introduced

In the December 2019 edition of "State of Valhalla," Goetz introduced "new top interfaces" IdentityObject and InlineObject:

To distinguish between inline and identity classes at compile time and runtime, we introduce a pair of restricted interfaces: IdentityObject and InlineObject. Inline classes implicitly implement InlineObject; identity classes implicitly implement IdentityObject.

JDK-8237069 ("[lworld] Introduce and wire-in the new top interfaces") captures the need to write these interfaces and Srikanth Adayapalam has added these new interfaces to repo-valhalla. Adayapalam describes these changes in the post "[LWorld] Definition and wiring in of the new top interface types.," which includes a link to the changeset. This changeset includes the new interfaces IdentityObject and InlineObject. From this new source, we can see that both interfaces are in the java.lang package and both interfaces have no methods defined ("marker" or "tagging" interfaces similar to java.io.Serializable).

The Javadoc for IdentityObject simply states, "A restricted interface implemented by all identity objects." Similarly, the Javadoc for InlineObject simply states, "A restricted interface implemented by all inline objects."

 

Conclusion

Project Valhalla continues to progress and developments in recent months create a feeling that Valhalla design and implementation is solidifying.

Saturday, August 3, 2019

Project Valhalla Eclairs

Éclairs offer several appealing characteristics and have been described as a "trifecta" that "encompass[es] the trinity of pastry, a light and crispy shell, a silky creamy filling and intense chocolate glaze." In the OpenJDK valhalla-spec-experts mailing list, Brian Goetz's post "Collapsing the requirements" proposes the concept of Valhalla "Eclairs" and discusses how use of these "eclairs" in Valhalla can provide their own trifecta of removing the need for LV in the VM ("LPoint/QPoint distinction" or boxed projection versus unboxed projection or "LV is the null-adjunction of QV"), removing the need for V? in the language, and removing the need for null default values.

Goetz's "Summary" in the "Collapsing the requirements" summarizes the value of the proposed Valhalla eclairs and succinctly states what the proposed "eclairs" concept is (I have added the emphasis), "In one swoop, we can banish LV from the VM, V? from the language, and null-default values, by making a simple requirement: every value type is paired with an interface or abstract class 'box'. For most values, this can be automatically generated by the compiler and denoted via a well-known name (e.g., V.Box); for some values, such as those that are migrated from reference types, we can explicitly declare the box type and pick explicit names for both types."

Goetz provides more details and examples in the "Collapsing the requirements" post of "requiring that every value type have a companion interface (or abstract class) supertype." He also provides a more formal definition:

Define an envelope-class pair ("eclair") as a pair (V, I) such that:
  • V is an inline class
  • I is a sealed type
  • I permits V (and only V)
  • V <: I

Several other Goetz statements in the "Collapsing the requirements" post highlight desirable features of these proposed Valhalla eclairs and here is a sample:

  • "If every value type be a member of an eclair, we can use V when we want the flattenable, non-nullable, specializable type; and we use I when we want the non-flattenable, nullable, erased 'box'. We don’t need to denote `V?`; we can just use I, which is an ordinary, nominal type."
  • "Now, the type formerly known as `V?` is an ordinary, nominal interface (or abstract class) type. The user can say what they mean, and no magic is needed by either the language or the VM."
  • "Using the eclair wrapper also kicks the problem of erased generics down the road; if we use `Foo<I>` for erased generics, and temporarily ban `Foo<V>`, when we get to specialized generics, it will be obvious what `Foo<V>` means (their common super type will be `Foo<? extends I>`). This is a less confusing world, as then 'List of erased V' and 'List of specialized V' don’t coexist; there’s only 'List of V' and 'List of V’s Box'."

One last aspect of the "Collapsing the requirements" post that I want to highlight here is the proposal to "define a new public value class `Opt<T>` which is the value half of the eclair, and the existing Optional is the interface/abstract class half." Goetz explains that the new value class Opt is needed as a compromise (rather than adapting existing reference class Optional to be the inside of the eclair) because "existing variables of type Optional are not flattened" when today's Optional is migrated to an eclair.

Although it is a bit of a compromise to have to know, use, and differentiate another type Opt from Optional, one of the advantages of having Opt be the value portion of the eclair and having Optional be the interface/supertype portion of the eclair (and the support of boxing conversion between them) is that there is a relatively straightforward migration path between today's use of Optional and tomorrow's use of Opt. As Goetz puts it, "existing fields / arrays can migrate gradually to Opt, as they want the benefit of flattening; existing APIs can continue to truck in Optional." Goetz summarizes the migration benefit and cost of the Opt approach: "Users can migrate their fields gradually. The cost: the good name gets burned. But there is a compatible migration path from ref to value."

It's a bit disappointing to need to use "Opt" instead of "Optional", but I think most Java developers could quickly become used to applying Opt when it's available and its advantages are identified. Today's powerful Java IDEs could also identify places where existing Optional usage can be changed to Opt and warn the developer when he or she tried to introduce an Optional reference class when an Opt value class could be used.

Eclairs are tasty, tempting treats and the proposed Valhalla "eclairs" have some tempting characteristics of their own.

Saturday, July 6, 2019

Project Valhalla: A First Look at LW2 Inline Types

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.

CharacteristicInline Type Wrapping Integerjava.lang.IntegerCustom Integer Wrapper
Inline?truefalsefalse
Indirect?falsetruetrue
Nullable?falsetruetrue
Final?truetruefalse
== Valid for Equality?truefalsefalse
toString()Implicitly CustomizedExplicitly CustomizedUses Object's
hashCode()Implicitly CustomizedExplicitly CustomizedUses 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).

Friday, July 5, 2019

Valhalla LW2 Progress - Inline Types

There has been significant public-facing progress in the past few weeks (June/July 2019) for Project Valhalla's LW2 phase/prototype originally proposed in October 2018. In this post, I briefly summarize some of the messages, documents, and Valhalla Early Access Builds that have been released recently. LW2 is described in the Valhalla Wiki page as an early prototype that "[moves] inline types into the existing type system."

Draft LW2 (JVM) Spec

Dan Smith announced "a first look at a preview-feature-quality spec for values/inline classes" on the valhalla-spec-experts mailing list in a message titled "Draft LW2 spec." That message sought feedback on the initial specification and has been updated based on that feedback. This is a work-in-progress, but the URL http://cr.openjdk.java.net/~dlsmith/inline-classes is currently setup to redirect to the current version of the draft specification.

Everything related to Valhalla is a work-in-progress and might change at some point, but it is interesting to read in this draft spec the direction Valhalla is currently headed from the JVM specification perspective. Here is a sample of some of the document's more interesting points (that are subject to change):

  • "This document describes changes to the Java Virtual Machine Specification, as modified by Improved Treatment of JVM Types, to support inline classes."
  • "There are five kinds of reference types: identity class types, inline class types, array types, interface types, and the Object type. Their values are references to objects."
  • "Most reference types are nullable, meaning the special null reference (representing the absence of an object) is a value of the type. Some reference types are null-free, meaning that null is not a value of the type."
  • "An identity class type names a non-inline, non-interface class defined in a class file (excluding the special class Object). Identity class types are nullable."
  • "An inline class type names an inline class defined in a class file. For each inline class, there is a nullable and a null-free inline class type; these types share the same set of values, with the exception of null."
  • "An array type consists of a component type with a single dimension (whose length is not given by the type). The component type of an array type may be boolean, any numeric type, or any reference type. Array types are nullable."
  • "An interface type names an interface defined in a class file. Interface types are nullable."
  • "The Object type names the Object class. The Object type is nullable. ... Instances of the Object class have identity but no fields, and behave like identity class instances."
  • "The default value of a nullable reference type is null. The default value of a null-free inline class type is a reference to a class instance whose fields all have the default value for their type."

OpenJDK Valhalla Wiki: L-World

The OpenJDK Valhalla Wiki page "L-World" asks and answers the questions "What Are Inline Types?" and "What is the L-World Project?" In answering those questions, the page currently describes Inline Types as "small, immutable, identity-less types" that were "formerly known as 'Value Types'" and are now known as "inline-types." The current page describes the "L-World Project" as "a series of early prototypes for bring[ing] Inline Types to the language and JDK" that "builds on work of the previous Minimal Values Types prototype (MVT)."

OpenJDK Valhalla Wiki: LW2

The OpenJDK Valhalla Wiki page "LW2" describes the LW2 prototype as "an iteration of a previous prototype, adding further language support and JDK API support for 'inline types' (formerly referred to as 'value types')." The page indicates that the LW2 prototype is based on the JDK 14 branch and the page includes several current characteristics of "inline types," some of which I list here:

  • "Inline Types may not declare an explicit super class (except Object)."
  • "All instance fields of a inline class are implicitly final."
  • "'Indirect' projections of inline types via the '?' operator."
  • "javac automatically generates hashCode, equals, longHashCode and toString computed solely from the instance's state and not from its identity"
  • "javac allows comparison of inline type using ==, !="
  • "Inline Types can not be assigned null, null can not be cast to or compared with inline types With the exception of an 'indirect' reference using the '?' operator."
  • New methods to potentially be added to java.lang.Class: isInlineClass(), asPrimaryType(), asIndirectType() / isIndirectType(), asNullableType() / isNullableType().
  • Inline types cannot be synchronized on, cannot be serialized, cannot reference themselves as direct fields, and cannot be assigned null.

Valhalla Early Access Builds

As of this writing, the Valhalla Early Access Builds page (now renamed "Project Valhalla 'L-World Inline Types' Early-Access Builds") features "Build jdk-14-valhalla+1-8 (2019/7/4)." The page opens with the paragraph, "This is an early access build, from Project Valhalla, aimed at testing a prototype implementation of L-World Inline Types." The page also mentions, "This build is based on an incomplete version of JDK 14." As is typical for early access builds, there are limitations and disclaimers regarding use of an early access build. It sounds like there are plans to periodically update these builds "with bug fixes and performance updates."

OpenJDK Valhalla Wiki: LW2 Command Line Options/p>

For developers wanting to test out the LW2 prototype, command-line options are listed in the OpenJDK Valhalla Wiki page "LW2 Command Line Options." As stated on the page itself, it "describes the command line for the experimental Java compiler, the Java launcher and HotSpot JVM for the support of L-World LW2 Inline Types in the Valhalla project."

Meeting Minutes from 19 June 2019 Valhalla Expert Group Meeting

Karen Kinnear has provided meeting minutes from the 19 June 2019 Valhalla Expert Group Meeting that provide insight into design topics on the minds of the expert group ("nullable", "flattenable", "inlinability", "specialized generics"). The notes indicate that the LW2 specification draft discussion is not intended to finalize all design decisions.

Conclusion

There's still quite a bit of work required for "inline types" (formerly "values types") to be fully introduced to Java. However, the current focus on "inline types" and the artifacts and builds associated with this concept are evidence that progress is being made in a concrete direction.

Monday, April 22, 2019

OpenJDK on GitHub

Project Skara was created "to ... investigate alternative SCM and code review options for the JDK source code, including options based upon Git rather than Mercurial, and including options hosted by third parties." The OpenJDK skara-dev mailing list included a post from Robin Westberg last week that announced, "We have added some additional read-only mirrors of a few different OpenJDK project repositories to the https://github.com/openjdk group..."

The read only OpenJDK repositories on GitHub will likely be more convenient for developers wanting to take advantage of the "open source" nature of OpenJDK to take a peek at its internals. More developers are likely to be comfortable with Git than with Mercurial. The GitHub-hosted repositories make it even easier to clone a given repository or to even fork it.

As of this writing, there are currently nine public repositories hosted on the OpenJDK GitHub site:

This is not the first time the OpenJDK has been mirrored on GitHub. There are 11 repositories in "Mirror of OpenJDK repositories": jdk (2017), jdk7u-jdk (2012), jdk7u (2012), openjdk-mirror-meta (2015), corba (2015), jaxp (2015), jdk7u-langtools (2012), jdk7u-jaxws (2012), jdk7u-jaxp (2012), jdk7u-hotspot (2012), and jdk7u-corba (2012). There is also a Project-Skara/jdk that was last updated in August 2018.

Project Skara is not finished and active development of OpenJDK continues on the Mercurial-based version control system. However, the availability of important OpenJDK repositories on GitHub should make it more convenient for Java developers to analyze OpenJDK source code.

Thursday, April 4, 2019

New Valhalla Developments: Forwarders and Poxes

In the post "Updated VM-bridges document" on the valhalla-spec-experts OpenJDK mailing list, Brian Goetz provides, "an updated doc on forwarding-reversing bridges in the VM." This was a topic at the late March 2019 Burlington (Massachusetts) Valhalla Offsite. A nice summary of Burlington Valhalla Offsite is provided by Karen Kinnear, in which she records that Goetz discussed "migration" using "field bridges" and "method bridges" as part of L20 phase of the new Valhalla phasing approach. Goetz's post adds significant background details. In this post, I reference a few of the more interesting points made in these posts, but both posts provide significantly more details than I'm providing here and are worth reading for anyone interested in the direction of Project Valhalla.

Forwarders

Although Goetz spends the majority of his post discussing the "migration aspects" of "forwarding+reversing bridges" and the of "forwarders," I found the historical background he provided in the introductory paragraphs to be a clean, concise summary of how we got to where we are now. Here are some brief statements from this historical section of the post that stood out to me (quotes here are very slightly modified for emphasis and to provide links):

  • "In the Java 1.0 days, `javac` was little more than an 'assembler' for the classfile format, translating source code to bytecode in a mostly 1:1 manner."
  • "Over time, we've seen small divergences between the language model and the classfile model, and each of these is a source of sharp edges."
  • "In Java 1.1 the addition of inner classes, and the mismatch between the accessibility model in the language and the JVM (the language treated a nest as a single entity; the JVM treat nest members as separate classes) required "access bridges" (`access$000` methods), which have been the source of various issues over the years."
  • "Twenty years later, these methods were obviated by Nest-based Access Control [jep181] -- which represents the choice to align the VM model to the language model"
  • "In Java 5, while we were able to keep the translation largely stable and transparent through the use of erasure..."
  • "... there was one point of misalignment; several situations ... could give rise to the situation where two or more method descriptors -- which the JVM treats as distinct methods -- are treated by the language as if they correspond to the same method."
  • "To fool the VM, the compiler emits "bridge methods" which forward invocations from one signature to another. And, as often happens when we try to fool the VM, it ultimately has its revenge."
  • "Java 5 introduced the ability to override a method but to provide a more specific return type. (Java 8 later extended this to bridges in interfaces as well.)"

After providing the historical background and summarizing the issues associated with these historical developments, Goetz moves onto to providing significantly more details about "bridge methods." He discusses the "anatomy of a bridge method" (forwarding/invokevirtual) and points out that "bridges are brittle" because "separate compilation can move bridges from where already-compiled code expects them to be to places it does not expect them." I particularly like Goetz's concise summary of the fundamental brittleness problem with bridge methods:

The basic problem with bridge methods is that the language views the two method descriptors as two faces of the same actual method, whereas the JVM sees them as distinct methods. (And, reflection also has to participate in the charade.)

Goetz discusses in his post the "limits of bridges" and points out that their limits are mostly encountered when attempting to migrate in a binary compatible fashion:

The problem of migration arises both from language evolution (Valhalla aims to enable compatible migrating from value-based classes to value types, and from erased generics to specialized), as well as from the ordinary evolution of libraries.

After providing some specific examples of where bridge methods fail migration attempts for fields and overridden methods, Goetz introduces "fowarders":

In this document, we attempt to learn from the history of bridges, and create a new mechanism -- "forwarders" -- that work with the JVM instead of against it. This raises the level of expressivity of classfiles and opens the possibility of greater laziness. It is possible that traditional bridging scenarios can eventually be handled by forwarders too...

Goetz devotes the remainder of the post to specifics of forwarders such as their invocation, using forwarders with fields, overriding forwarders, adaptation of forwarders, and type checking and corner cases associated with forwarders.

Poxes: Value Type Wrappers for Primitives

There was more discussed in the Valhalla Offsite than forwarding. One of Kinnear's notes that stood out to me stated, "Poxes: value type wrappers for primitives." Since the introduction of "autoboxing and unboxing" in JDK 1.5, Java developers have become comfortable with the conceptual relationship of "boxed"/"wrapper" reference types to their primitive counterparts. Therefore, it does make some sense to me to use similar terminology for the concept of value type "wrappers" of primitive counterparts being called "poxes." Goetz describes "poxing" in the post "Finding the spirit of L-World" and calls "creating a value box for primitives" "a 'pox'" and discusses the possibility of "adjust[ing] the compiler's boxing behavior (when boxing to `Object` or an interface)" to "prefer the pox to the box."

Updating Valhalla Value Types Phases

In her post "Updated phasing of Valhalla Value Types," Kinnear outlines Valhalla value types "Phases/AIs for Proposals" discussed at the Burlington Valhalla offsite meeting mentioned earlier. She calls out one major timing proposal in its own paragraph (I added the emphasis):

One important phasing is moving null-default value types and migrating value-based-classes to null-default value types was moved out to L20, which is after the initial preview.

Kinnear provides a list of "phases/APIs" categorized under one of three general milestone allocations: L10, L20, and L100. The two specific topics covered in my post (forwarding and poxes) appear to be currently proposed for L20.

Conclusion

Valhalla's value types are still a ways out before we'll see them in a General Availability JDK, but I appreciate the significant effort being invested in these value types and look forward to benefiting from them at some point in the future.

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.

Tuesday, July 31, 2018

JVM Language Summit 2018 and Valhalla EA Build 0

July 2018 ended with some interesting developments related to the future of Java and the JVM. JVM Language Summit 2018 was held at Oracle's Santa Clara campus on the last two days of the month and Build 0 of the Project Valhalla "L-World Value Types" Early-Access Builds was released on July 30.

JVM Language Summit 2018

Videos of presentations from the JVM Language Summit 2018 are available on YouTube. The easiest way to access these videos is via the JVM Language Summit 2018 Playlist. The recorded presentations include the following:

Valhalla Early-Access Builds: Build 0

The Project Valhalla page now offers an early access build of the Valhalla Project. This first early access build, Build 0, was posted on July 30. The first three paragraphs of the page with this Build 0 tell us that this build is "aimed at testing a 'Value Types' implementation within the JVM" (L-World Value Types), is "provided as a convenience so that they [expert users interested in Project Valhalla] don't need to build from the source code (branch 'lworld')", and is "based on an incomplete version of JDK 11."

The Build 0 Project Valhalla Early Access Build is available as a gzip-ed TAR file for Linux/x64, Windows/x64, and macOS/x64. Although there is a long list of limitations associated with this Build 0 early access build, I'm still looking forward to playing with it.

Wednesday, June 27, 2018

Looking into Java's Future: Empty Value Types

Although the promising Java value types are not imminent, I still enjoy nosing around occasionally in the OpenJDK valhalla-dev mailing list to see how things appear to be progressing and to get an idea of what is to come. Admittedly, there are some discussions that are beyond my understanding given my limited exposure to the terms used and the low-level specifics of some of these messages. However, there are occasionally messages and threads that I understand well what is being written and find interesting. A recent example of this is the "Empty value type ?" thread.

Rémi Forax starts the thread by asking "Is empty value type targeted for LW1?" The example error message included with that question shows a LinkageError and ClassFormatError with the message "Value Types do not support zero instance size yet". The response to this question from Tobias Hartmann answers, "No, empty value types are not planned to be supported for LW1."

Before moving onto the rest of the thread [which is the part that interested me the most], I'll quickly discuss "LW1." In a message on that same OpenJDK mailing list called "[lworld] LW1 - 'Minimal LWorld'", David Simms states, "we are approaching something 'usable' in terms of 'minimal L World' (LW1)" and "we will be moving of prototyping to milestone stabilization." That same message states that the "label" is "lw1" and the affected-version and fixed-version are both "repo-valhalla". In other words, "LW1" is the label used to track bugs and issues related to work on the "minimal L world" implementation. You can reference John Rose's 19 November 2017 message "abandon all U-types, welcome to L-world (or, what I learned in Burlington)" for an introduction to the "L World" term and what it means in terms of value types.

Returning to the "Empty value type?" thread, Kirk Pepperdine asked a question that also occurred to me, "How can a value type be empty?" He added, "What is an empty integer? An empty string?" He said he was "just curious" and now I was too. Here is a summary of the informative responses:

  • Rémi Forax: "type [that] represents the absence of value like unit, void or bottom"
  • Rémi Forax: "type that represents the result of a throw"
  • Rémi Forax: "type that allows HashSet<E> to be defined as HashMap<E,Empty>"
    • Brian Goetz's message elaborates on the value of this: "Zero-length values can be quite useful, just not directly. Look at the current implementations of Set that delegate to HashMap; all that wasted space. When we have specialized generics, they can specialize to HashMap<T, empty>, and that space gets squeezed away to zero."
  • Rémi Forax: "transformative type like a marker type that separate arguments" (see message for example of this one)

I also liked the final (as of this writing) Kirk Pepperdine message on that thread where he summarizes, "Feels like a value type version of null."

Incidentally, there are some other interesting messages and threads in the June 2018 Archives of the valhalla-dev mailing list. Here are some of them:

I look forward to hopefully one day being able to apply value types in my everyday Java code. Until then, it is interesting to think of what might be and also to see how much work is going into making it so.

Thursday, April 12, 2018

Updates on Records (Data Classes for Java)

There have been several updates related to "Java Data Classes" (AKA "Records") in recent months. As I briefly mentioned in the post "Updates on JavaFX, Valhalla, Data Classes, and Java's Floating-Point," Brian Goetz's "Data Classes for Java" "explores possible directions for data classes in the Java Language." Sadly, despite significant discussion on this potential new Java feature on the OpenJDK mailing lists, this document also points out, "This is an exploratory document only and does not constitute a plan for any specific feature in any specific version of the Java Language."

In mid-March, Goetz posted a message to the amber-spec-experts mailing list titled "Records -- current status." He states the intent of records in Java in that message: "Our goal all along has been to define records as being 'just macros' for a finer-grained set of features. Some of these are motivated by boilerplate; some are motivated by semantics (coupling semantics of API elements to state.) In general, records will get there first, and then ordinary classes will get the more general feature."

There are several interesting points made in the "Records -- current status" post, but I'll focus on a few here that I found particularly interesting. In general, one can see in the stated early design decisions that general principles that are now more popular than perhaps they were when Java was created dominate the thinking related to records.

Under the section "Mutability and accessibility," Goetz proposes that Java records provide final fields that are "package (protected for abstract records) by default," but which would allow the developer to "explicitly opt out of (non-final)" as well as allow accessibility to be "be explicitly widened (public)." I love the idea of a Java construct having final fields by default and having to explicitly choose to make them non-final rather than the other way around that we've become used to in Java.

In the "Accessors" section, Goetz writes that the current thought is to have these accessor methods NOT use the JavaBeans convention of "get" and instead use the field's name without "get" prefix. He writes, "The obvious choice is to expose read accessors automatically. (These will not be named getXxx; we are not burning the ill-advised Javabean naming conventions into the language, no matter how much people think it already is.) The obvious naming choice for these accessors is fieldName()." I like the idea of automatically generated read accessors following this simple naming convention (which I tend to use when I write builders). I also appreciated the emphasized reassurance that there is no conspiracy or effort to "burn the ill-advised JavaBean naming convention into the language."

Goetz's "Core methods" section talks about common methods such as equals(Object), hashCode(), toString(), and so forth. Goetz writes that "Records will get equals, hashCode, and toString" and that "there's a good argument for making equals/hashCode final." He adds that while there's no need to make toString() a final method, the automatically generated read accessor methods could be made final.

Stephen Colebourne has contributed multiple posts to the mailing list discussion regarding records/data classes in Java. These include his insights from presenting on Amber (the project housing this effort along with other efforts such as LVTI and raw string literals) and a response to the previously mentioned original "Records -- current status" message.

Other relatively recent mailing list messages regarding records in Java include Goetz's "Records: construction and validation," a discussion started by Remi Forax on "Record and annotation values," and a thread started by Gunnar Morling called "Records -- Using them as JPA entities and validating them with Bean Validation."

Although Records/Data Classes are not yet associated with any particular Java release, it's exciting to think about the possibilities they might bring to enable better, safer, and more readable Java code.