SIP-15 and multi-field value classes

153 views
Skip to first unread message

Jeremy Bell

unread,
Jan 3, 2013, 4:14:17 PM1/3/13
to scala...@googlegroups.com
This is more of a question than a suggestion, regarding SIP-15, value classes. First of all, thanks to everyone involved - even with its current limitations, SIP-15 is a great addition to the language.

My question is whether multi-argument constructors for value classes is a planned feature for a future incarnation of this SIP? This can be worked around somewhat by storing, for instance, two floats in a double value, etc... but it is cumbersome for uses cases that need it (vectors for physics simulations, etc...). 

The JVM may not have native support for it (yet), but my naive thoughts are that it could be simulated even without native support, with some major limitations, and yet still be incredibly useful:

class Vector2d(val x: Double, val y: Double) extends AnyVal {...}

val i = new Vector2d(1.0, 0.0);
// equivalent to:
// val _i_x = 1.0; val _i_y = 0.0;


// This would always have to be inlined to avoid boxing, or else return a boxed instance of the class
def add(left: Vector2d, right: Vector2d) : Vector2d = new Vector2d(left.x + right.x, left.y + right.y)

val j = new Vector2d(0.0, 1.0);
val k = add(i, j);
// although the add function instantiates boxed values for arguments and the return value,
// the compiler can inline this call into:
// val _j_x = 0.0; val _j_y = 1.0;
// val _k_x = _i_x + _j_x; val _k_y = _i_y + _j_y;

def lengthSquared(v: Vector2d) : Double = v.x * v.y
// could be equivalent performance-wise to:
// def lengthSquared(_v_x: Double, _v_y: Double) = _v_x * _v_y

Collections would of course be tricky, but you could use the traditional solution: multiple arrays of primitives to simulate an array of value types with multiple primitive fields:
var l = new Array[Vector2d](3)
// could be equivalent to:
// var _l_x = new Array[Double](3); var _l_y = new Array[Double](3);

Passing arrays, also similar:
def someVectorArrayAccumulator(vl: Array[Vector2d]) = ...
// could be equivalent to:
// def someVectorArrayAccumulator(_vl_x: Array[Double], _vl_y: Array[Double]) = ...

However, aside from arrays, I think any other generic container (especially if it has more than one type argument) would end up requiring boxing for multi-field value classes, which is unfortunate:

new Tuple2(new Vector2d(1.0, 0.0), new Vector2d(1.0, 0.0)); // should either not be possible or else automatically result in boxing Vector2ds, at least until/unless the JVM supports value tuples natively

Jesper Nordenberg

unread,
Jan 3, 2013, 4:52:57 PM1/3/13
to scala...@googlegroups.com, Jeremy Bell
There was a discussion about multi-field value classes recently in
scala-debate. The problem with the inlining solution is that there are
many cases where it's not applicable (problems occur with virtual method
calls, deep call hierarchies (for example Hotspot will not optimize
methods larger than a certain size), field access rights etc.). I'm not
saying it's not beneficial to do it in some cases, but we need JVM
support for multiple return values or tuple types to eliminate 100% of
the heap allocations. This must be the goal of all implementations of
value types as stack allocation performance is deterministic while heap
allocation performance is not.

/Jesper Nordenberg
Reply all
Reply to author
Forward
0 new messages