If I understood the Scala documentation correctly “Value classes” can extend universal traits but extending traits requires to allocate memory (Universal traits allow basic inheritance of methods for value classes, but they incur the overhead of allocation).
What is not clear in the documentation is the circumstances where the memory allocation is required (systematically or when a method of the trait is called). So I think the documentation could be more detailed on this specific point.
Now my question: I was wondering if the boxing/instantiation of value class could be avoided when the universal trait is sealed.
It would allow to have multiple value classes extending a fixed set of methods. The methods of the “sealed universal trait” could eventually inlined in the singleton generated by the compiler.
That’s strange. I thought instantiation wasn’t necessary as long as the static type of the variable on which you invoke a method is a value class. But indeed:
scala> trait Foo extends Any { def foo = 42 }
defined trait Foo
scala> class MyInt(val a: Int) extends AnyVal with Foo
defined class MyInt
scala> object Bar { def bar(i: MyInt) = i.foo }
defined object Bar
scala> :javap -cp -filter Bar
......
public int bar(int);
Code:
0: new #14 // class MyInt
3: dup
4: iload_1
5: invokespecial #35 // Method MyInt."<init>":(I)V
8: invokevirtual #39 // Method MyInt.foo:()I
11: ireturn
......
But when you override foo it does work:
scala> class MyInt(val a: Int) extends AnyVal with Foo { override def foo = super.foo }
defined class MyInt
scala> object Bar { def bar(i: MyInt) = i.foo }
defined object Bar
scala> :javap -cp -filter Bar
.......
public int bar(int);
Code:
0: getstatic #35 // Field MyInt$.MODULE$:LMyInt$;
3: iload_1
4: invokevirtual #38 // Method MyInt$.foo$extension:(I)I
7: ireturn
........
I would think enough information is available at compile time to generate the necessary forwarder methods in both cases.
EDIT
Oh wait, there’s still boxing I see:
public final int foo$extension(int);
Code:
0: new #14 // class MyInt
3: dup
4: iload_1
5: invokespecial #29 // Method MyInt."<init>":(I)V
8: invokevirtual #33 // Method MyInt.$line13$$read$MyInt$$super$foo:()I
11: ireturn
In hindsight, I guess it’s probably not possible to generate the $extension method in the general case, because the implementation of foo is not always available to the compiler. The sealed trait thing is probably not the worst idea then.
@Jasper: on my machine “:javap -cp -filter Bar” does not work but I have similar results when executing “:javap -c Bar.class” or “:javap -c MyInt$.class”