
Java 10 – Specification for Value Types - groodt
http://cr.openjdk.java.net/~dlsmith/values.html
======
filereaper
The following bytecodes have been introduced: vaload vastore vbox vdefault
vload vreturn vstore vunbox vwithnewfield

These will have direct impact on the JVM. Is there a test version of the JVM
with these bytecodes already implemented? Not sure if Java follows similar
rules as the IETF, show us working code with the specifications.

~~~
jimktrains2
If they're doing breaking changes to the VM, I wonder if we can get rid of
type erasure. Generics seem really nice until you actually use them to do
anything mildly complicated, then type erasure rears it's ugly head and you
now have a type parameter and a Thing.class normal parameter and reflection.

~~~
nradov
Those are not breaking changes. Existing byte code will continue to work.

My understanding of generic type erasure is that it is more of a language
issue than a VM issue. Nothing in the VM prevents reified generics, but when
generics were introduced in Java 5 they decided to use type erasure in order
to avoid having to produce a whole new collections standard library or break
compatibility with existing code.

~~~
jimktrains2
I meant breaking in that the Java 10 compiler would be targeting a newer
version of the JVM and could dispense with having to be backwards compatible,
which was one of the reasons I remember reading for generics.

They could have simply left the old library, deprecated it, and added in their
genericed one as a a new package. It had to be modified anyway.

~~~
evincarofautumn
Right, it breaks _forward_ compatibility: bytecode for a newer VM won’t work
on an older VM. IMO backward compatibility is much more important for a
programming language, though.

------
karianna
Hi all - interested in early access builds and / or helping out? Head to
OpenJDK.java.net and join the Valhalla project and the Adoption Group.

Disclaimer - I help run the adoption group and maintain the Valhalla wiki.

------
nullnilvoid
This title is hugely misleading. The value types specification is for JVM, the
platform, not Java 10. You can compile a large number of source languages to
run on JVM, such as Java, Scala, Closure, Groovy, Kotlin, Javascript etc. just
to name a few.

~~~
WatchDog
Is it really misleading though?

Does anyone with the slightest familiarity with JVM languages not understand
that each major Java language version is also associated with a major JVM
version?

~~~
nullnilvoid
Given that we are not even close to the official release of Java 9 and whether
the proposal to JVM specification will be accepted and implemented for which
version, it is largely inaccurate to title the article "Java 10 -
Specification for Value Types" for a JVM change proposal. Besides,
interchangeably referring to JVM and Java reflects the ignorance about the
whole ecosystem of JVM languages.

~~~
WatchDog
Well the specification explicitly talks about version 54 class files, which it
then goes on to state "Version 54.1 class files are intended to be supported
only by implementations of Java SE 10.". It's not going to land with Java SE
9.

~~~
nullnilvoid
With all the prolonged delays of features in Java, whether it is Java 10, 11,
or 12 is still in question. As an instance, Jigsaw was proposed to be a
driving feature of Java 7, and then delayed to Java 8 and even Java 9. And
recently it was voted "No" by IBM, Red Hat etc.

~~~
WatchDog
Sure, features slip, but value types are coming in java 10 until they aren't.

------
moomin
In its own way this is a sad day. Yes, Java's getting better, but it marks
another nail in the coffin for the dream of a smart compiler. In this case,
escape analysis never lived up to its promise.

~~~
lolive
Could you elaborate on what a smart compiler is?

~~~
mike_hearn
A
[http://wiki.c2.com/?SufficientlySmartCompiler](http://wiki.c2.com/?SufficientlySmartCompiler)
in this case would be a compiler capable of automatically converting classes
into value types such that the developer did not have to think about this
detail of memory management themselves.

I felt the same slight sadness when I saw the complexity of the planning
involved in Java value types, and the many-year path to get there.
Intuitively, a sufficiently smart compiler _should_ have been able to take
care of this, and in some cases it does do. So it's worth reflecting on why
adding new opcodes and such is necessary.

HotSpot and some other JVMs can do an optimisation called "scalar
replacement", which converts objects into collections of local variables which
are then subject to further optimisation. So for example a Triple<A, B, C>
type class could be converted into three variables, then the optimiser notices
that the second element of the triple was never actually used anywhere, and
eliminates it entirely.

Scalar replacement is one of several optimisations that relies on the output
of an escape analysis. Escape analysis is a better known term so people often
use the name of the analysis to mean the name of the optimisations it unlocks,
although that's not quite precise. Sometimes people talk about stack
allocation, but that isn't quite right either. Only objects that don't
"escape" [the thread] can be scalar replaced.

There are several reasons this isn't enough and why Java needs explicit
support for value types.

Firstly, the JVM implements two different EA algorithms. The production
algorithm that is used with the out of the box JIT compiler (C2) is somewhat
limited. It can identify an object as escaping just because it might escape in
some situations, even if it often doesn't. There is a better algorithm called
"partial escape analysis" implemented in the experimental Graal JIT compiler,
but Graal isn't used by default. In Java 8 it requires a special VM download.
It'll be usable in Java 9 via command line switches. PEA can unlock
optimisation of objects along specific code paths within a method even if in
others it would escape, because it enables the un-optimisation of escaped
objects back onto the heap.

Graal unfortunately can't be just dropped in. For one, you don't just replace
the entire JIT compiler for a production grade mission critical VM like
HotSpot. It may take years to shake out all the odd edge case bugs revealed by
usage on the full range of software. For another, Graal is itself written in
Java and thus suffers warmup periods where it compiles itself. The ahead-of-
time compilation work done in Java 9 is - I believe - partly intended to pave
a path to production for Graal.

Implementing PEA in C2 is theoretically possible, but I get the sense that
there isn't much major work being done on C2 at the moment beyond some neat
auto-vectorisation work being contributed by other parties. All the effort is
going into Graal. I've heard that this is partly because it's a very complex
bit of C++ and they're afraid of destabilising the compiler if they make major
changes to it.

Unfortunately even with PEA, that still isn't enough to replace value types.

(P)EA can only work on code that is in-memory when the compilers optimisation
passes are operating, and moreover, only in-memory in the form of compiler
intermediate representation. In a per-method compilation environment like most
Java JITCs that means it can only work if the compiler inlines enough code
into the method it's compiling. Graal inlines more aggressively than C2 does
but it still has the fundamental limitation that it can't do inter-procedural
escape analysis.

It can be asked, why not? What's so hard about inter-procedural EA?

That's a really good question that I wish John Rose, Brian Goetz and the
others had written a solid full design doc or presentation on somewhere.
They've said it would be incredibly painful, and obviously view the Valhalla
(also incredibly painful) path as superior, so it must be hard. In the absence
of such a talk I'll try and summarise what I learned by reading and watching
what's out there.

Firstly, auto-valueization - which is what we're talking about here - would
necessitate much, much larger changes to the JVM. Methods and classes are the
atoms of a JVM and changing anything about their definition has a ripple
effect over millions of lines of C++. HotSpot isn't just _any_ C++ though -
it's one of the most massively complex pieces of systems software out there,
with big chunks written in assembly (or C++ that generates assembly). The Java
architects have sometimes made references to the huge cost of changing the VM.
They clearly perceive changing the Java language as expensive too, but
compared to the cost of changing HotSpot, it can still be cheaper to
complicate the language. Frankly it sounds like Java is groaning under the
weight of HotSpot - it's fantastically stable and highly optimised, but that
came at large complexity and testing costs that have to be considered for
every feature. Part of the justification for doing Graal is that the JITC is
the biggest part of the JVM and by rewriting it in Java, they win back some
agility.

As an example of why this gets hard fast, consider that the compiled form of a
"valueized" version of a parameter is different to the reference form. Same
for return value (a value can be packed into multiple registers). So you
either have to pick a form and then box/unbox if the compiled version doesn't
'fit' into the call site, or compile multiple forms and then keep track of
them inside the VM to ensure they're linked correctly. And a class that embeds
an array may wish to be specialised to a value-type array, but then you need
to detect that and auto-specialise, detecting any codepaths that might assume
reference semantics like nullability or synchronisation, and then you have to
be able to undo all that work if you load a new class that violates that
constraint.

Secondly, detecting if something can be converted into a value type (probably)
requires a whole program analysis. Java is very badly suited to this kind of
analysis because it's designed on the assumption of very dynamic, very lazy
loading of code. Not just because of applets and other things that download
code on the fly, but it's quite common in Java-land for libraries to write and
load bytecode at runtime too. Also Java users and developers expect to be able
to download some random JAR and run it, or a random pile of JARs and run it,
with essentially no startup delay. HotSpot can run hello world in 80
milliseconds on my laptop and the very fast edit-run cycle is one of the
things that makes Java development productive relative to C++.

All that said, applets are less important than they once were, and Java 9 does
introduce a "jlink" tool that does some kinds of link-time optimisations:

[https://docs.oracle.com/javase/9/tools/jlink.htm#JSWOR-
GUID-...](https://docs.oracle.com/javase/9/tools/jlink.htm#JSWOR-GUID-
CECAC52B-CFEE-46CB-8166-F17A8E9280E9)

[https://gist.github.com/mikehearn/930e3001e76415ae1e2d85dcdf...](https://gist.github.com/mikehearn/930e3001e76415ae1e2d85dcdfc5d4eb)

~~~
frogboglog
That's a long post and I admit I didn't read all of it. But, is anything
you've said there a consideration for most "business" software? I can
understand on a cache-hitting trading app perhaps.

~~~
moomin
It's important if you care about GC pauses (which you will eventually). Take a
look at this report from the .NET based stack overflow guys:
[http://blog.marcgravell.com/2011/10/assault-by-
gc.html?m=1](http://blog.marcgravell.com/2011/10/assault-by-gc.html?m=1)

Note that they solved their problems using exactly the features being added in
Java 9.

------
Cieplak
C++ has had these things for years.

Seriously though, the JVM is killing it. Can't wait until I can compile my
.jar to verilog and run it on my FPGA, or send the verilog to TSMC and get
some ASICs printed out.

~~~
repsilat
> _C++ has had these things for years._

C++ is _built_ on these things. The "value type" thing informs everything
about the language. I love it, and it's my go-to language when something just
has to be fast, but it comes along with some hefty baggage. Java gets a lot of
mileage out of its reference-first philosophy that C++ would be wise to try
out -- the "everything must be possible with no overhead" philosophy of the
language bleeds into the programming community in unhealthy ways, and the
amount of language machinery to make the value stuff work "as well as
possible" ([https://stackoverflow.com/questions/3601602/what-are-
rvalues...](https://stackoverflow.com/questions/3601602/what-are-rvalues-
lvalues-xvalues-glvalues-and-prvalues)) is absurd.

> _Seriously though, the JVM is killing it_

As for the JVM and Java, this seems like a guilty admission that the CLR and
C# ate their lunch a decade ago (perhaps not wrt performance, but for language
features....) I've never worked in the Microsoft stack, but the stories have
been the same since the dawn of the age -- "C# is Java with real generics,
value types and lambda functions." First they laughed...

~~~
Matthias247
As great as structs in C# for performance reasons are: They also provide
several new ways to shoot yourself in the foot if you don't understand their
behavior to 100%.

One example that I run many years ago was having a struct Foo { int x; } which
was nested inside a List<Foo> myList. Trying to mutate one list element with
syntax like myList[0].x = 27 silently failed, because the indexer of the list
returns a copy of Foo and you mutate that inside of writing it back. Nowadays
its a compiler error, but back then it wasn't. The workaround is something
like "Foo f = myList[0]; f.x = 27; myList[0] = f;". Which is quite weird if
you are coming from C++. From a C# point of view it's actually obvious, since
you can't pass around references and pointers to structs inside of other
things - and if you also add this functionality, you get lots of the
complexity from C++ back (references to structs, functions/properties that
return references, questions around reference lifetimes, etc.). Without having
also reference semantics for structs, structs also can't achieve the kind of
performance which "value types" in C++ have, since they sometimes need to be
copied fully.

Another nice gotcha is the surprising behavior of readonly structs, which e.g.
is documented here: [https://bytes.com/topic/c-sharp/answers/261922-readonly-
beha...](https://bytes.com/topic/c-sharp/answers/261922-readonly-behavior-
structs)

For those reasons I think it's quite fair that Java and other languages did
not immediately jump onto the value types train. I think introducing them
carefully, and trading off the performance gains against the amount of new
complexity in the language is fine.

~~~
pjmlp
When Java was introduced we already had plenty of GC enabled languages with
value types.

Eiffel, Oberon, Modula-2+, Modula-3, VB, are just a few examples.

Hence why I always saw as lost opportunity not to provide them in first place.

------
netheril96
What is the use of value types if it cannot be the argument of generics?

~~~
valarauca1
Many

[http://cr.openjdk.java.net/~jrose/values/values-0.html](http://cr.openjdk.java.net/~jrose/values/values-0.html)

~~~
pseudoramble
This was handy to glance through. Thanks!

I did notice one point that struck me as odd (under "Details, details"):

> Can a value class implement interfaces? Yes. Boxing may occur when we treat
> a value as an interface instance.

I don't normally think of values in other languages as having methods directly
or an interface like this. I wonder what the primary reasons for this would
be. Backwards compatibility might be one reason.

~~~
pjmlp
A few examples are D, C#, VB, F#, Eiffel, Delphi, C++, Rust.

~~~
pseudoramble
Thanks for the examples. Seems clear that I don't fully understand it then,
but it's good to know that it's common so I can look around some more.

------
pedrow
Does anyone how this would work if there were two value types with the same
members/definition but from different libraries - would they be interoperable?
For example, a mathematical function library and a chart plotting library
might both define complex numbers. It would be good if you didn't have to
write (trivial) conversion functions every time you wanted to use them
together, like you do now. (I think this is called 'structural typing'?)

~~~
kodablah
It appears not and that's a good thing here. Java is based on explicit typing
and I do not expect things to work w/ implicit conversions between value
types. Granted, that doesn't mean that a JVM implementation may not have a
higher performing way to perform a cast between two of the same struct. There
is of course boxing/unboxing that comes w/ converting between value and ref
classes.

------
saagarjha
Looks cool, but I didn't see Java 10 anywhere. What's the timeframe for this?
Is this truly a part of Java 10, considering that Java 9 is still in
development?

~~~
sverhagen
The new release date is September 21: [https://jaxenter.com/java-9-schedule-
change-sept-134484.html](https://jaxenter.com/java-9-schedule-change-
sept-134484.html)

It's been moved a lot and AGAIN, but I believe "the target is starting to move
slower" :)

------
pulse7
Why not just "value types" and "value class types" instead of long "direct
value class types"?

~~~
Retra
Because references are values.

------
cosmosgenius
Is there a TL:DR version of this?

~~~
zyx321
Java 10 may support defining your own primitives.

e.g. You could define a tuple-like type that will get passed and stored by
value. Now you can make a billion member Array of 'em and not incur the speed
and memory overhead you'd get from using Objects that need to be tracked,
dereferenced, garbage-collected, etc...

------
exabrial
<3 Java and Java EE! Glad to see the innovation wheels turning

