Everytime Pos
will be treated as an Ordered[Pos]
, allocation will happen.
There are several cases when allocation has to happen, see http://docs.scala-lang.org/overviews/core/value-classes.html#when_allocation_is_necessary.
So when doing something as simple as calling <
, you will get allocations:
val x = Pos( 1 )
val y = Pos( 2 )
x < y // x & y promoted to an actual instance (allocation)
The relevant rules are (quoted from the above article):
Whenever a value class is treated as another type, including a universal trait, an instance of the actual value class must be instantiated
and:
Another instance of this rule is when a value class is used as a type argument.
Disassembling the above code snippet confirms this:
0: aload_0
1: iconst_1
2: invokevirtual #21 // Method Pos:(I)I
5: istore_1
6: aload_0
7: iconst_2
8: invokevirtual #21 // Method Pos:(I)I
11: istore_2
12: new #23 // class test/Position$Pos
15: dup
16: iload_1
17: invokespecial #26 // Method test/Position$Pos."<init>":(I)V
20: new #23 // class test/Position$Pos
23: dup
24: iload_2
25: invokespecial #26 // Method test/Position$Pos."<init>":(I)V
28: invokeinterface #32, 2 // InterfaceMethod scala/math/Ordered.$less:(Ljava/lang/Object;)Z
As can be seen we do have two instances of the "new" opcode for class Position$Pos
UPDATE: to avoid the allocation in simples cases like this, you can manually override each method (even if they only forward to the originlal implementation):
override def < (that: Pos): Boolean = super.<(that)
override def > (that: Pos): Boolean = super.>(that)
override def <= (that: Pos): Boolean = super.<=(that)
override def >= (that: Pos): Boolean = super.>=(that)
This will remove the allocation when doing x < y
by example.
However, this still leaves the cases when Pos
is treated as an Ordered[Pos]
(as when passed to a method taking a Ordered[Pos]
or an Ordered[T]
with T being a type parameter). In this particular case, you will still get an allocation and there no way around that.