A fairly in depth proposal for value types by John Rose, Brian Goetz, and Guy Steele. Would be nice to see this in Java 9 or even sooner.
If you can’t wait for Java 9 (and Java 10, which will be the performant one :point:), and want to tinker with a subset of the functionality described in the proposal, you can take a look at my impl:
Value types combined with stack allocation:
// surprise! no object creation Vec3 struct = new Vec3(x, y, z); struct.x += 33.77; boolean a = (vec instanceof Vec3); // false boolean b = (vec != null); // true System.out.println(struct); // "<struct@386745454>" Vec3 vecs = new Vec3[n+100]; // stack allocated too // note: no looping to fill the array vecs.x = 56.f; vecs = vecs; // no copy! process(vecs, vecs, vecs.toString()); Vec3 mapped = StructEnv.map(Vec3.class, byteBuffer);
Stack allocated structs are pointer based (no scalar replacement) on memory regions tied to threads (not ThreadLocals).
Struct arrays use indirection, so you can nullify slots, assign arbitrary structs to slots, pass arrays or array elements as parameters to methods, even if the method parameter is defined to be an Object, like System.out.println(Object), yes, really.
An issue with the Java 9 proposal seems that value types are ‘final’ (makes sense), so to use them as structs, the compiler (javac) will do boxing/unboxing like with primitives (since java 5). This, to my knowledge, means mass-object-allocation, for which you can only hope Escape Analysis => Scalar Replacement will finally be reliable when Java 9 is released…
I’m not confident it will be usable for games - yet.
One of the main uses of value types might be in developing complex memory-efficient structures, which is going to need some way to do “pointers to structs” … wonder how they might solve that one (haven’t read the paper in depth - has anyone else given it a fine examination?)
The problem with the current proposal seems to be that you can’t have pointers/references to value types. So yes, it’s a problem for non-linear data structures. More discussion here.
There is no way that they will ship this for pre Java 9.
value types are “persistent” like Strings or Java 8 date/time types. By “use them as structs”, you want traditional field modification. Why? Can’t you just write your class like any other persistent class? I don’t see where you think Java would do boxing on value types.
I guarantee you that these will be usable for games. Point, vector, matrix would all use this. So would general purpose tuple types. An Optional value type would be useful as well.
The main purpose of this whole concept is the efficiency you gain by not having a pointer. For the scenarios where you really need pointers, keep using regular class.
The JVM doesn’t allow direct pointers/references to primitives like ints and floats without workarounds. That doesn’t seem to be a problem.
Data structures like linked lists require recursive references and fundamentally could not use this value type construct.
This looks like C# structs with the big difference being the mandatory requirement of (immutable) persistence.
The official Microsoft guidelines for choosing between classes vs structs (http://msdn.microsoft.com/en-us/library/ms229017(v=vs.110).aspx) says only use a struct when:
- It logically represents a single value, similar to primitive types (int, double, etc.).
- It has an instance size under 16 bytes.
- It is immutable.
- It will not have to be boxed frequently.
Microsoft recommends you only use structs with immutable values, but the language doesn’t require it. This Java proposal requires persistent immutability. The downside of having large structs is that pass-by-value copy operations become expensive. When the runtime has a guarantee of immutability, it can internally pass by reference instead.
Persistent data structures are inherently thread safe and logically easy to work with, but I don’t see what other advantage that requirement provides. There must be some advantage or the Java proposal wouldn’t require it, but I don’t see what that is.
Even the relatively new tuple classes introduced in C# 4.5 uses regular classes, not structs, just like you would do in current versions of Java. I wonder why?
Also, even third party “Option” types in C# all seem to use classes, not structs. And Scala with its limited value type support, doesn’t use value types for Option and implements Option as a regular class.
The lack of ability to perform limited pointer arithmetic is one of the biggest problems for the JVM.
Stack allocated and/or mapped mutable datastructures are invaluable for high performance games, where copying all your vertex attributes into a VBO is a waste of CPU cycles. If you map structs into the same memory region the ‘copy’ is free. I also can’t see myself doing vector math with value types… for every operation you have to figure out how to get the value(s) back to the callsite(s). Without mutable state you’ll feel severely restricted, and the game related use cases disappear quickly.
Can you point to an example of such a data structure?
Working with persistent vectors shouldn’t be any more difficult than working with immutable ints/floats/doubles. Can you show me a simple code example that illustrates the complexity with persistent types?
Randomly choose a paper on cache-oblivous data structures.
Derailing back to Riven’s original reply.
I only very briefly skimmed the outer layers, but LibStruct looks really interesting!
When you say stack allocation, does that mean that you do the equivalent of scalar replacement? If so, are there any clever tricks to ensure that the intermediate representation doesn’t grow too big for the JIT to optimize - apart from fiddlling with XX:MaxInlineSize etc?
I’m assuming the Vec3 class in the code snippet is one’s own and not something out of an external library - or is it possible to allocate “normal” classes on the stack too (via external configuration or similar)? Would be super-useful, though maybe not plausible.
No, there is no scalar replacement. That’s exceptionally hard to accomplish. Everything is based on pointers, just like with ‘normal’ stack allocation in C, where the stack is just another region of main memory.
And yes, you can define your own structs, just like the readme.md shows on GitHub.
So far it doesn’t support nested structs yet (shouldn’t be hard) but it will probably never support flattened nested structs.
Sorry, by “normal” classes I meant classes that came from an external library; would be neat to if it were possible to retrofit those too but that might be much harder.
There is actually support for that, eventhough annotations are out of the question with external code.
Instead of structdef.txt looking like this:
feed it this:
their.clazz.TheirStruct SIZEOF 20 their.clazz.TheirStruct FIELD x F 0 their.clazz.TheirStruct FIELD y F 4 their.clazz.TheirStruct FIELD z F 8
(F = float)
It’s very unlikely that a 3rd party class would be suitable to be used as a struct. There is just theoretical support ^.^
Heh, must experiment with this during the weekend!
I was thinking along the lines of libgdx’s vector classes. Right now I’m using my own, more constrained struct-like approach, but it results in having to re-implement a lot of the math utility classes.
The great is the enemy of the good and all that… I can’t help but thinking that mapped objects in bytebuffers would have given us everything we needed, and escape analysis and scalar replacement would have given everybody else what they really needed, and it would have been much more easy for them to implement. libstruct looks like a more useful solution to more people than the value types proposal in many ways.
I’ve only very quickly skimmed it. It looks like the motivation here is when we hit many-cores (hundreds, thousands) and is targeting functional style multi-threaded as a scalability solution…but maybe I’m misreading it.
That’s an understatement. C# makes it impossible, because structs always have an implicit no-args constructor which doesn’t initialise any of the fields (even if you define a no-args constructor which does initialise them). I’ve was bitten by that at least once.
In my LibStruct I run the actual constructor (not just a default constructor), but disabled running the (default!) struct-constructors when allocating arrays and mapping structs to buffers.
In the case of mapping structs to buffers, you really don’t want the constructors to run (as they’d overwrite the mapped memory) but I still have to decide whether running default constructors when allocating arrays is the right thing to do.
new Vec3(); // stack-alloc, run static method: <_init_>(I)V new Vec3(3, 5.6f, 7); // stack-alloc, run static method: <_init_>(IFFF)V new Vec3[n] // stack-alloc, no constructors are run (yet...) StructEnv.map(Vec3.class, bb) // no constructors are run
I must admit that i don’t really see me using anything outside mapped objects in bytebuffers. I also would expect more C like behaviour with something called a struct. ie no Constructors ever. But then if there are references in the struct?