days
-3
-6
hours
-2
-2
minutes
-4
-1
seconds
0
-1
search
Why value types are important

The new ValueType in Java

Peter Verhas
Java
©Shutterstock / JustDOne

Java, as it is now, has two different types of data—primitives and objects. In the coming releases, there will be a new type that is called ValueType. For everyday programming, there should be no difference between objects and value types but under the hood they are really different. They are like objects but work as if they were primitives. The second part of the sentence means: they are effective. Other languages have this type of data handling, though they usually do not call them with this name.

In this article, I will talk about the issues with objects that make it necessary to have value types in Java. After that, I will talk about what value types are, and finally, I will talk about the issues that value types have. Yes, value types also have issues and the reason for that is very fundamental. You cannot have all the good things in life. You cannot have your cake and eat it. There are advantages using value types over objects but there are applications, programming constructs, where objects fit better. In this last part of the article, you will also understand why there are restrictions on value types, like no inheritance, lack of generics, and immutability.

Objects in Java

Objects in Java are small memory parts that are usually stored in the segment of the memory that is called heap. The memory is allocated when the object is created and freed when the object is not used anymore and is collected. During the lifetime of the object, the memory that represents the object may be moved from one place to another during the garbage collection process. This is how Java manages the memory and ensures that—no matter how objects are created and destroyed—the memory does not get segmented. Other languages that collect garbage but don’t do the compacting face the risk of long-running processes segmenting the memory. Something for something: compacting is a CPU-intensive process, which is why Java GC hardly competes with the speed of the Go language garbage collection. Most importantly, however, the fact that the objects are moving in the memory makes pointers useless. They point somewhere in the memory but the data may be somewhere else already after a compacting phase of the GC. That is the reason why Java does not use pointers. Java uses references.

You can ask what the difference is between pointers and references. Well, references are administered pointers. When the GC moves an object in memory, it has to update all the references so that they will all know where the object is at that moment. Integration with native code is also a bit cumbersome. The Java GC cannot know where the native code was copying the pointer in the memory managed by the native code. Also, there is no pointer arithmetic in Java. There are arrays, but other than that, you can just forget the nice pointer arithmetic that you could get used to when programming in C or C++. The benefit is that you can also forget memory corruption caused by erroneous pointer value calculations.

SEE ALSO: Does 32-bit or 64-bit JVM matter anymore?

Nevertheless, the objects are in the memory and when the processor needs to do some calculation with it, the object has to travel from the main memory to the processor. It was not an issue back in the day when CPUs were running 4MHz. The speed of memory access was comparable with the speed of the processor. Today, processors run 4GHz and the memory access is hardly any faster than it was in old times. This is not bad technology, rather physics. Calculate the time needed to travel from the CPU to the memory and back with the speed of light—and that is it. There is only one way to speed it up: put the memory closer to the processing unit. And actually, that is what modern CPUs do: they have memory caches on the CPU itself. Unfortunately, not only the CPU speed increased, but also the need for memory. In old times, we had 640kB on a computer and it had to be enough for everybody. Today my Mac has 16GB. Physics come again: you cannot put 16GB or more on the CPU because there is no room and also there is no effective way to cool the system, and we want to use the CPU to calculate and not to cook.

When the CPU needs a memory location, it reads into the cache. When a program needs something from the memory, it is likely that soon it will need something from the next memory location, and so on. Therefore, the CPU goes ahead and reads whole memory pages into the cache. There can be many pages in the cache from different memory areas. When we have an array and are accessing the first element, it may be slow (in CPU terms slow means a few tens of nanoseconds), but when we need the second element from the array, it is already in the cache. And it is very effective, except when this is an array of objects. In the case of an array of objects, the array itself is a continuous area of references. The CPU accessing the second element of the array will have the reference in the cache, but the object itself may be on a totally different page than the page where the first object was. There are some memory layout optimization techniques to solve this issue partially, but the real deal would be if the objects were stored lined up in the memory like the partridges after hunting. But they cannot be. Even if they were lined up one after the other in the memory, they would be separated by the so-called object header.

The object header is a few bytes ahead of the object memory that describes the object. It holds the lock that is used in synchronized statements, and also the type of the object. When we have a reference in a variable that is, for example, of the Serializable type, we will not know the actual type of the object from the variable itself. We have to get access to the object, and the Java runtime will read the actual type of the object. For Java, this object header helps in inheritance and polymorphism. Also, the few bytes in the 32bit implementations amount to 12bytes and to 16bytes on 64bit architecture. This means that an Integer stores a 32bit int value and additionally 128bit of extra administrative bits. That is a 4:1 ratio.

ValueType

Value types try to solve these issues. A value type is something like a class as far as it can have fields and methods.

Value types are being developed for Java within the Valhalla project under JEP 169. Currently, there is an early access version available to give it a try. This version is a branch off from the Java 11 version of Java and has some limitations. The syntax is preliminary with some keywords starting with a double underscore that cannot be in the final release and some features that are not implemented. Nevertheless, the possibility to give it a try is there.

What makes the value type different from an object is that the value type does not have an object header or an identity, there are no references to a value type, value types are immutable, and there is no inheritance between value types—and for this reason, there is no polymorphism. Some of these, like the lack of an object header, are an implementation detail, while others are design decisions. Let’s look at these features of value types.

No identity

Value types do not have an identity. When we are dealing with objects, two objects can be identical. Essentially, we are just speaking about the same object twice and objects can be equal. In the latter case, we have two different objects, but they are instances of the same class and the equals() method returns true when we compare them. Identity is checked using the == operator in Java, and equality is checked, as we already mentioned, with the equals() method. Primitives, like byte, char, short, int, long, float, double or Boolean also do not have an identity. In this case, this is fairly obvious. Saying that two Boolean values are both true but still different instances is nonsense. As logical values, numbers like zero, one, or pi do not have instances either. They are values. We can compare them using the == operator for equality and not for identity. The idea of value types is to extend the set of these eight primitive values with programmer-defined types that also represent values.

No references

The values are stored in the variables and not in the heap. When the bit representation of the value is in a variable, the compiler will know the type—just like it knows that the bits in a variable should be handled as a 32bit signed integer number when the type of the variable is int. It is also important to note that when a value type is passed to a method as an argument, the method will receive the “copy” of the original value type. This is because Java passes all arguments by value and never by reference. This will not change with the introduction of value types. When a value type is passed as an argument to a method call, all the bits of the value type are copied to the local argument variable of the method.

No object header

Because value types are values, stored in the variables and not in the heap, they do not need a header. The compiler just knows what type a variable is and in what way the program should handle the bits in that variable. This is crucially important when the value type arrays come into the picture. Just like in the case of the primitives, when we create an array of a value type, the values are packed one after the other in the memory. This means that with value types we will not have the problem that object arrays have. There are no references to the individual elements of the array and they cannot be scattered in the memory. When the CPU loads the first element, it loads all the elements that are on the same memory page and accessing consecutive elements will use the advantage of the processor cache.

No inheritance

There could be inheritance between value types, but it would be extremely difficult to manage by the compiler and would not bring many benefits. I dare say that allowing inheritance would not only cause issues to the compiler but would also lure inexperienced programmers into creating constructs that would do more harm than good. In the upcoming Java version, which supports value types, there will be no inheritance between value types or between classes and value types. This is a design decision and to explain among the many reasons let us look at some simple examples.

When a class C contains a field of the type of another class P, it contains a reference to that other class. It can also be that C is the child of the P parent class. This is not a problem. For example, there is a linked list of P instances. There is a field called next that is either null or holds the reference to the next P in the list. If the list can also contain instances of C (remember: C extends P) then C also has a reference to the next P. The list can contain C instances because, as the inheritance implies, a C is also a P.

What is the situation if P is a value type? We cannot link the elements together. There is no reference to the next P because there is no such thing as a reference to a value type. Classes can reference each other via field values. Value types implement only containment. When a value type has a field that is of another value type, it will contain all the bits of that other value type. A value type, therefore, can never contain a field that is of its own type. It would mean that the value type contains itself and this is an infinite recursion in the definition of the type. Such a type would be infinitely large and is therefore explicitly forbidden in the specification. If value types could inherit from each other, the restriction would be more complex. In that case, we could not simply say that a value type must not contain itself. We should have forbidden any other value type that is a descendant of the current value type.

Also, try to imagine a variable that is of the type V. Such a variable should be large enough to hold all the bits of V. But it should also be large enough to hold all the bits of K if it were possible to extend value objects and K would hypothetically extend V. In that case, K will contain all the bits of V and some more of its own. How many bits should a variable of the type V have? The number of bits of V? Then we cannot store a K value in it, K would not fit. All variables of type V should be large enough to also hold a K. But we should not stop at K since there could be more value types that extend K, still assuming that there was inheritance, which there is not. In that case, a variable of the type V should have as many bits as the largest descendant of V could have, which is unknown at the time of the compilation. It becomes known only when all the value types are loaded.

No polymorphism

Since there is no inheritance, there cannot be value type polymorphism. However, there are more reasons that suggest that it is not reasonable to implement polymorphism for value types. Let’s look at the example above and imagine the variable that can hold all the bits of the largest descendant of V. When we call a method on this variable, which one should we invoke during runtime? The variable does not hold information about the actual value type’s type. Is it V, is it K or some other descendant? The compiler has to know which method to call because there is no header information that would signal the type that is in the variable at that moment.

Immutability

Immutability is a design decision, but it is a natural way. Value types in Java are immutable. Immutability is generally a good thing. Immutable objects help a lot with coding in a clean and thread-safe way. Immutability does not solve all the problems, but many times it is handy. Also if you think about an int as a number, it is fairly obvious that you cannot change its value. If a variable holds the integer value 2, then you can change the value stored in the variable but you cannot change the value itself to 3. If you could, then suddenly 2 times 2 would be nine in the whole universe. The similar philosophy holds for value types. You can change the content of the variable that holds the value type, but you do not change the value type itself. When you change a single bit then essentially, by philosophy, you created a new value type and stored the new value in place of the old one. Have a look at the following simple example (Listing 1):

package javax0.valuetype;

public __ByValue class Point {
    public int x;
    public int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Point pushedRight(int d) {
        return __WithField(this.x, x+d);
    }

    public String toString() {
        return "[" + x + "," + y + "]";
    }
}

This is a simple value type that uses a preliminary syntax that was compiled using the build 11-lworldea+0-2018-07-30-1734349.david.simms.valhalla version of the early access Java. It makes it possible to “push” a point along the X axis. The main program using it does that, as seen in Listing 2:

package javax0.valuetype;

public class Main {

    public static void main(String[] args) {
        Point a = new Point(3,4);
        a = a.pushedRight(1);
        System.out.println(a);
    }
}

When we invoked pushedRight, the variable a got a new value. The point (3,4), however, did not move, the two-dimensional space did not get distorted. That point remains there forever, only the variable value is changed. If we now try to change the line a = a.pushedRight(1); to a.x = 4;, we get a compilation error that says (Listing 3):

/.../src/javax0/valuetype/Main.java:7: error: cannot assign a value to final variable x

Note that the field x was not declared final, but since it is in a value type, it is automatically final.

The immutability as a feature correlates strongly with the fact that there can be no references to a value type. Java could theoretically allow us to modify a field of a value type. The result would essentially be the same: we get a different value. This way, immutability in case of value types is not a restriction. It is only a matter of how we write our program, and how we think of value types. Thinking of them as values like numbers, which are immutable by essence, is deemed to be a healthy way of thinking.

Give it a try

You can download the early access release. The JEP homepage is https://openjdk.java.net/jeps/169 and you can download the EA release from https://jdk.java.net/valhalla/. The builds are available for Linux, macOS and Windows for the x64 platform. The installation may not be as simple as in the case of the commercial products, but for experienced Java developers some environment variable settings, manual file extraction and moving to the right place should not be a problem.

You can try to use Eclipse, IntelliJ or Notepad to edit the source code, but at least with IntelliJ 2019.EA edition I could not build the code. Even though the code is a fork from the Java 11 source, IntelliJ recognizes it as Java 13, which is, by the way, a little hint where we can expect value types in the released version. Compilation of the code can be done manually executing command line javac commands and then the java command to start the JVM. I could manage to get along with the IntelliJ extracted ANT script even though I am more familiar with Maven than ANT.

SEE ALSO: The State of Java in 2019: “The rate of change is higher than ever before”

Playing around, I experienced some inexplicable compilation errors when I assumed there was no error in the code. Then, changing the code, the compilation went fine. Other times, when the mistake was undoubtedly on my side, the error messages were descriptive and easy to understand.

Summary

Java is developing rapidly. There are many new things that surfaced in the last two years and there are many new things in the making that will be available in the future. The value types feature is one of them. This article described the main characteristics of this feature and gave a short peek into this new technology. Java is also a major programming language, perhaps it is the second most widely used programming language in the professional environment after COBOL. Being a Java developer is almost a sure thing as far as employment is concerned. Being professional and being up-to-date, however, requires constant learning. Luckily, Java is open source and there are a freely available open mailing list, documentation and source code—and trial versions of upcoming versions are available long before the release date. A keen developer has to look at these, use the EA versions to experiment and be prepared to know the possibilities at the time the releases become GA for commercial work. Go, grab Valhalla EA version of Java and experiment!

Author
Peter Verhas
Peter Verhas is a Senior Software Architect at EPAM Switzerland. He has more than ten years of Java development experience and more than twenty years with C and other programming languages. He is the author of the books Java Projects, Mastering Java 9 and Programming Java 9 by Examples. He regularly blogs in English (at DZONE, Java Code Geeks and his own blog Javax0.wordpress.com). Peter has a Master’s degree in Electrical Engineering and studied at TU Budapest, TU Wien, and TU Delft. He worked for companies like Digital Equipment Corporation, T-Mobile supporting telecom and finance industries and he was a teacher at TU Budapest for a short period. Peter also publishes open source programs on github.com/verhas and is the author of the ScriptBasic interpreter.

Leave a Reply

1 Comment on "The new ValueType in Java"

avatar
400
  Subscribe  
Notify of
Alexander Orlov
Guest

“This is because Java passes all arguments by value and never by reference.”

The last time I checked Java it was not pass by value nor pass by reference. In fact it was both. If you pass primitives as arguments, Java is “pass by value” as primitives do not have a reference. But if you pass an object, Java is “pass by reference” as the method receives and modifies the Object that was passed.