JEP 390: Warnings for Value-Based Classes

OwnerDan Smith
TypeFeature
ScopeSE
StatusCandidate
Discussionvalhalla dash dev at openjdk dot java dot net
EffortS
DurationXS
Reviewed byBrian Goetz
Endorsed byBrian Goetz
Created2020/07/08 21:39
Updated2020/09/24 21:17
Issue8249100

Summary

Define a @ValueBased annotation, apply it to classes in the Java Platform API that may become inline classes in a future release, and provide warnings about improper attempts to synchronize on instances of such classes. Deprecate the constructors of the primitive wrapper classes for removal in order that these classes may be considered @ValueBased classes.

Motivation

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.

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. Specifically, a candidate inline class has the following properties:

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.

The primitive wrapper classes (java.lang.Integer, java.lang.Double, etc.) satisfy most of these constraints, but have public constructors that clients can invoke to guarantee a unique identity (e.g., for Integers used as locks). These public constructors have been deprecated since Java 9. If we now deprecate them for removal then the primitive wrapper classes can safely be considered value-based classes.

When a value-based class becomes an inline class, its instances will be == based on their fields' values, and attempts to synchronize will throw an exception.

These changes may be inconvenient for some, but the workarounds are straightforward: If you need an identity, use a different class—often one you define yourself, but Object or AtomicReference may also be suitable. The benefits of migrating to inline classes—better performance, reliable equality semantics, unifying primitives and classes—will be well worth the inconvenience.

It will be helpful to warn developers of these risks several releases before the migration occurs. We therefore propose to standardize the value-based class terminology with an annotation, apply it to candidate inline classes in the JDK, and provide warnings to developers who synchronize on instances of such classes.

Description

The java.lang.ValueBased annotation interface will be introduced to indicate a class, interface, or method result for which no instances are expected to rely on object identity. The annotation declaration will describe the constraints outlined above, and communicate to developers that they should exercise caution when using == or identityHashCode, and should not perform synchronization.

The @ValueBased annotation may be applied to the following declarations in the Java Platform API and the JDK:

To make the primitive wrapper classes satisfy the constraints of @ValueBased classes, we will deprecate their constructors of for removal. (These constructors were originally deprecated in Java 9.)

The following warnings will alert developers using these APIs that synchronization may fail in a future release:

The monitorexit bytecode and the Object methods wait, notify, and notifyAll will thrown an IllegalMonitorStateException if invoked outside of a synchronized statement or method. There is thus no need for warnings about these operations.

For example:

@ValueBased final class Distance {
    final double meters;
    private Distance(double meters) { this.meters = meters; }
    public Distance ofMeters(double m) { return new Distance(m); }
}

Distance d = Distance.ofMeters(20.0);
synchronized (d) { ... } // javac warning & HotSpot warning
Object o = d;
synchronized (o) { ... } // HotSpot warning

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.

javac might also implement warnings for @ValueBased classes that violate the constraints of a @ValueBased class (non-final instance fields, toString method inherited from Object, etc.)

Alternatives

We could abandon efforts to migrate these classes to be inline classes. However, there are significant benefits that developers will enjoy when we complete the migration, and the relative impact on developers who depend on problematic behavior is quite small.

Dependencies

Migrating @ValueBased classes to be inline classes will require a reasonable amount of lead time with these warnings in place.

Most significantly, a JEP to make the primitive wrapper classes inline will depend on completion of this JEP.