Project Valhalla - "Codes like a class, works like an int."

In 2014, Java engineers started developing project Valhalla in order to introduce more flexible data types into the Java programming language. Project Valhalla consists of three main parts: value classes, primitive classes, and specialized generics. None of these functionalities have yet been applied, but the delivery of the first part is expected in 2023. All of the functionalities are expected to be delivered by 2025.

post-image

Every object-oriented programming language starts off with the premise that “everything is an object”, which is not usually the case. Have you ever had an interview where you were asked something like: “Why isn’t Java a completely object-oriented programming language?” The answer is – that it contains primitive types like int, double, char, etc. Thus, we can say that an object is everything that can be defined by a user, but there are eight additional built-in types that aren’t objects, and new ones cannot be defined.

In Java, whenever we create a new object, it is unique and stored at a certain location in the memory. What we “see” is a reference, i.e. a pointer to that object. Every object can have one or more references pointing to it, which gives it its identity. And we all know what happens when there are no references. Once you create an object, it is unique, and during its life, it can change its properties, just like people – the older we are, the more we change, but we are still the same person.

The idea behind value classes is separating references from identities

Two value objects are considered equal when they have the same values, not when they have the same reference (the objects do not necessarily have to be the same). To put it plainly, two value objects are equal (==) when their attributes have the same values. Therefore, value classes are still classes and they have all of their properties, including being null, having fields, methods, constructors, superclasses (albeit with a few restrictions), nested classes, and interfaces… Also, they are still referent types – through a reference, we access value objects, but that reference does not signify its identity. By excluding identity from the classes that do not need it, we avoid an entire category of bugs.

Properties of value classes:
• A class is implicitly final, so it can’t be inherited.
• All value class fields are implicitly final, so their values can be added precisely once through a constructor.
• A value class cannot inherit an abstract identity class, or implement an identity interface, but it can inherit abstract value classes and implement value interfaces.
• No method can be synchronized.
• A class can be defined as a value class by adding a keyword:

value class Amount {
 private String currency;
 private int amount;
 public Amount(String currency, int amount) {
 this.currency = currency;
 this.amount = amount;
 }
 public Amount addTax(int taxValue) {
 return new Amount(currency, amount + taxValue)
 }
}

As we can see, there is not much difference in the definition of a value class compared to identity classes, but now, for example, we can use this:

Amount a1 = new Amount("RSD", 1000);
Amount a2 = new Amount("RSD", 1000);
if (a1 == a2) // true

Due to the fact that value objects have no identity, JVM can freely double and re-code them to improve the performance of calculation time, memory usage, and the garbage collector.

Primitive classes allow us to define new primitive types, with the same behavior that built-in primitive types have (in, double, long…). While value classes enable us to exclude identities, primitive classes enable us to exclude references.

primitive class Coordinate {
 long longitude;
 long latitude;
 Coordinate(long longitude, long latitude) {
 this.longitude = longitude;
 this.latitude = latitude;
 }
 Coordinate move(long z) {
 return new Coordinate(longitude + z, latitude + z);
 }
}

Primitive classes are special value classes whose instances can be represented as values of primitive type. The name of the class (Coordinate) is also a name of primitive type. As primitive classes have no reference, they cannot be null, and the default value has all fields set to their default values. As far as performances go, they are expected to be identical to the performances of the existing primitive types. However, current primitive types have their own wrapper classes, and we sometimes need to have reference types for the given primitive types. Thus, we can add the .ref keyword to a primitive class, to get:

Coordinate c = //primitive value 
Coordinate.ref c= //primitive reference

Therefore, Coordinate and Coordinate. ref corresponds to the declaration of the same class, and the values of both types are both instances of one Coordinate class. The connection between Coordinate and Coordinate. ref is similar to the connection between int and Integer, but in runtime, the conversion between the primitive value and the value objects is “cheaper” than the traditional boxing conversion. All of these innovations bring about another one – making specialized generics, like ArrayList. Currently, we can’t have, for example:

Set<int> ints = new HashSet<>()

or use any primitive type in a generic; making specialized generics was necessary.

This migration brings about lots of challenges (a primitive type is not an Object, hashCode() cannot be calculated, and there is no reference…), and this will be the ultimate thing that project Valhalla will deliver. By then, we will not be able to use natural notation like List or Optional, but we will certainly be able to use something like List. All of these changes are aimed at improving the performance of the programming language. With a well-defined primitive class, less CPU time is wasted, and the overall throughput is significantly increased.

We are yet to see how this plays out in practice, but early tests utilizing just some of the functionalities Valhalla offers show very promising results. For example, the implementation of a multiplication matrix is up to six times faster with Valhalla, and performing a loop sum is up to 12 times faster. This is not the only project that will improve Java as a programming language – there are other projects in progress: Amber, Lambda, Loom, Panama, etc.

Author of the text: Milos Paunovic, Senior Backend Engineer