26 ms·
Java 10 – Specification for Value Types
- filereaper 9y agoThe 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 9y agoIf 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.
- bitmapbrother 9y agoIsn't type erasure one of the reasons there are so many dynamic languages on the JVM? Also, why do you consider the introduction of these new bytecodes as breaking changes for the JVM? Backward compatibility has always been one of the highest priorities for the Java architects.
- paulddraper 9y ago> Isn't type erasure one of the reasons there are so many dynamic languages on the JVM? No and yes. No, it doesn't really matter for dynamically typed languages (just use Object for generic types). Yes, it matters for statically typed languages. One of the factors for Scala .NET abondonment was the difficulty in creating a interoperable advanced type system in a fully reified environment. IMO, full type erasure (like C/C++) is the right way to go. Java erasure is weird only because it didn't do it completely, not because they did it at all.
- bad_user 9y ago> No, it doesn't really matter for dynamically typed languages (just use Object for generic types). This line is disproven by all the dynamic languages that happened and failed on the CLR.
- kelnos 9y agoDid they fail because they weren't possible to build on top of the CLR, or because people didn't want to use them?
- Matthias247 9y agoWhat do you mean with "full type erasure (like C/C++)"? Afaik if you have RTTI enabled you have full type information available at runtime, even for templates - which is the thing that people usually want when talking about reified generics. Is it about C++ without RTTI? Or about the fact that vector<int> is compiled completely separate from a vector<string> (monomorphization)? I think the latter one is an orthogonal issue to whether type information is available at runtime.
- paulddraper 9y agoYou're right, since C++98, it's has RTTI. Subpar example on my part :/
- josefx 9y ago> No, it doesn't really matter for dynamically typed languages (just use Object for generic types). At which point any call to the underlying environment fails with a type error. Sorry your List<Object> is not and will never be a List<int>, trying to pass it as one wont do. Either you provide a way to construct a generic type with the right type parameters in the dynamic language or you accept that you can only inter-op with a limited subset of the underlying environment. Of course that also gets ugly. You now have to deal with the fact that you not only have a List but several incompatible List<T> floating around, adding the contents of two lists suddenly includes the question what sort of list to return, List<Int>,List<Double>,List<Number> or an error? In a type erased context the answer is always the same, you return a List<Object>.
- jimktrains2 9y agoI 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.
- kelnos 9y agoWhere are you reading that? The Java N compiler always targets version N of the JVM (well, by default, anyway), and you can't run bytecode on older versions of the JVM. I would sincerely doubt they're considering breaking back-compat in Java 10 (that is, making it so older bytecode targeting something <10 cannot run on 10+).
- devdoomari 9y agoscala handles the generic-edge cases using lower-bounds and upper-bound types - and scala runs on JVM. But there could be any other edge cases that cannot be solved easily thru scala's lower-/upper-bound types... (don't know enough)
- nradov 9y agoThose 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.
- deleted 9y ago[deleted]
- jimktrains2 9y agoI 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 9y agoRight, 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.
- moomin 9y agoYup, and Microsoft did exactly that, meaning C# has been able to express List<int> for ten years now.
- jdmichal 9y agoOr they could have done erasure in the runtime when they detected non-generic usage of a generic class. Instead of forcing it on everyone.
- valarauca1 9y agoNah this is a VM issue. Type assertions have no ability to recurse. RN you assert both classes are a UTF8 value in the constant pool. Or really 1 class is a UTF8 value, which the compiler know the first one is. But with Generics, you may not know what it holds at runtime so this doesn't work. You'd have to constantly rebuild the constant pool (Slow) each time a new _kind_ of generic is used. So either a new type+byte code would have to be introduced, or the type assertion instruction would have to become recursive. The later is a breaking change. Also interfaces break this b/c those are class specific. So a Lorg/my/company/myClass$5; and Lorg/your/company/yourClass$0 might both implement the same interface. But that interface information isn't in the collection class, but those to class's class files. So really it just needs new byte code.
- deleted 9y ago[deleted]
- bad_user 9y agoIt's in fact not type erasure that "rears its ugly head", but actually that Java's type system is not expressive enough, which is why developers end up relying on reflective capabilities. There's something seriously wrong with the type system when you want "instanceOf T" checks or "new T".
- kelnos 9y agoIf you don't have/want "new T", how do you ever create an instance of anything?
- chii 9y agoThe in this context is a variable, not a concrete type.
- barrkel 9y agoDid you mean: "The T in this context..."? Instantiating a generic type is like a function call at compile time, where the type arguments are substituted for type parameters in the body of the generic type. It's a variable at compile time, but it's a concrete type at runtime for any version of the code that can execute.
- barrkel 9y agoThere's nothing wrong with doing 'new T' in a generic method or class body. It requires a constraint on the type variable is all: that some constructor with a specific parameter list is available.
- alkonaut 9y agoI only thought the erasure was bad because of how Java lacked value types (so my list of T will use heap boxes when T is int). I haven't given it a ton of thought but I thought that apart from reflection it would actually be nicer if the runtime erased types. I.e. at runtime a type should just be either a stack/copy/move type or a reference type. So erase all reference type to objects. It feels like it's the job of the compiler to handle these. Obviously at runtime you can get some extra safety guarantees from reified types, but at the cost of languages on the runtime being more difficult to adapt to other paradigms etc. I imagine a runtime that doesn't have strong opinions about types to be easier to make type level language changes for (i.e. the language(s) can evolve without the need for runtime changes), and it should also be easier to support entirely different type systems.
- tigershark 9y agoErased generics are awful compared to proper generics like C#. If you ever used both of them it should be clear as the sun. In C# you don't have to pass around the type in a method parameter and use reflection. I’m missing how you can claim that the languages on the runtime with proper generics are more difficult to adapt to other paradigms given the extremely fast evolution of C# and F# compared to Java that for example received closures something like 10 years after C#.
- alkonaut 9y ago> In C# you don't have to pass around the type in a method parameter and use reflection. I know - but I'm not familiar with the situation where I'd have to to that in java. Do you mean e.g. Foo(object x) { if (X is List<int>) ... else ... }
- Sharlin 9y agoBasically every time you need to instantiate a type passed as a type parameter. You either need to pass the appropriate class literal or a factory function. And if you need ro create an instance of a generic type parameterized by a type parameter (eg. Collection<T>) you need a factory or else resort to raw types and/or ugly casting.
- PDoyle 9y agoThese aren't breaking changes. This isn't even the first time they've added bytecodes. (Java 7 added invokedynamic.)
- deleted 9y ago[deleted]
- _old_dude_ 9y agoIt has the same kind of rules, i believe, here is the code of the VM that works/may work with value types http://hg.openjdk.java.net/valhalla/valhalla/hotspot/ http://hg.openjdk.java.net/valhalla/valhalla/hotspot/
- netheril96 9y agoWhat is the use of value types if it cannot be the argument of generics?
- knappa 9y agoThat's another proposed change in Java 10, both part of Project Valhalla: http://www.jesperdj.com/2015/10/12/project-valhalla-generic-specialization/ http://www.jesperdj.com/2015/10/12/project-valhalla-generic-...
- valarauca1 9y agoMany http://cr.openjdk.java.net/~jrose/values/values-0.html http://cr.openjdk.java.net/~jrose/values/values-0.html
- bluejekyll 9y agoTuples! Finally. > Finalization. Finalization makes no sense for values and should be disallowed (though values may hold reference-typed components that are themselves finalizable.) This is a little disappointing. I was hoping that the lifetime of essentially stack based variables could be tracked, and finalization could be bound to the stack. That would be really powerful; though mind bending after beating so many Devs to not rely on finalization. Imagine wrapping a Closable object in a Closing tuple for instance, and that is guaranteed to run when the tuple goes out of scope.
- saagarjha 9y agoLooks 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 9y agoThe 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" :)
- WatchDog 9y agoThe specification refers to version 54.1 class files, version 54 corresponds to Java 10, `.1` being the inital minor version.
- geodel 9y agoI'd think Java 10 will be around mid 2020 or later.
- nullnilvoid 9y agoThis 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 9y agoIs 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 9y agoGiven 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 9y agoWell 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 9y agoWith 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.
- 9y ago
- exabrial 9y ago<3 Java and Java EE! Glad to see the innovation wheels turning
- Cieplak 9y agoC++ 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.
- eeperson 9y agoWhy wait: https://chisel.eecs.berkeley.edu/ https://chisel.eecs.berkeley.edu/
- Cieplak 9y agoChisel is very sweet, definitely the tool I would use to implement the JVM instruction set in silicon.
- repsilat 9y ago> 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-lvalues-xvalues-glvalues-and-prvalues https://stackoverflow.com/questions/3601602/what-are-rvalues...) 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...
- _old_dude_ 9y agoValue types doesn't seem to be like struct in C++ or C#. They are immutable so you have no way to know if they are stack allocated, split over several registers or on heap. This is important because it means that JITs will not have to be changed, they will not have to manage stack aliases like in C#/C++.
- karianna 9y agoHi 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.
- cosmosgenius 9y agoIs there a TL:DR version of this?
- _old_dude_ 9y agoIt's a patch to Java Virtual Machine spec in order to introduce value types, think like an immutable struct with methods attached. I suppose that at some point in the future, the Java language spec will be updated to let us play with that.
- zyx321 9y agoJava 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...
- pulse7 9y agoWhy not just "value types" and "value class types" instead of long "direct value class types"?
- Retra 9y agoBecause references are values.
- moomin 9y agoIn 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 9y agoCould you elaborate on what a smart compiler is?
- chii 9y agoa smart compiler is one where it can bridge the shortcomings or incompetence of the programmer such that you can be very much more stupid and still output decent code.
- louthy 9y agoWhich is what all compilers do (by optimizing and rewriting syntax trees to be more efficient)
- mike_hearn 9y agoA 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-CECAC52B-CFEE-46CB-8166-F17A8E9280E9 https://docs.oracle.com/javase/9/tools/jlink.htm#JSWOR-GUID-... https://gist.github.com/mikehearn/930e3001e76415ae1e2d85dcdfc5d4eb https://gist.github.com/mikehearn/930e3001e76415ae1e2d85dcdf...
- pedrow 9y agoDoes 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 9y agoIt 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.