Skip to content

Instantly share code, notes, and snippets.

@non
Last active January 2, 2018 18:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save non/95e4018352f4a36aaa1f1677c22c8154 to your computer and use it in GitHub Desktop.
Save non/95e4018352f4a36aaa1f1677c22c8154 to your computer and use it in GitHub Desktop.
Some notes about the interaction of SIP-23 with specialization.

introduction

I was asked to consider how specialization should interact with SIP-23. Here is a quick test I did with some thoughts on where we are now versus where we should be.

See tlc.scala for the code and tlc.bytecode for the Java bytecode that code produced (using Typelevel Scala with the -Yliteral-types flag enabled).

methods

The tlc.Demo code has four methods defined (which after specialization compile to six methods worth of bytecode).

Here is a breakdown of those six methods:

concrete

We can see that summoning ValueOf[1] produces a boxed value. This is not great, but if someone knows which singleton type they want at this moment they'd probably just write 1 so I don't think this is a big deal.

generic

This case does box. I think given the signature this ends up compiling to (A => A) there isn't a better option available in this case.

spec and spex

These methods are both the generic case of specialized methods, and have the same contours as generic above.

spec$mIc$sp

This method takes an (implicit) int parameter, and returns an int parameter, so from the signature (int => int) things seem fine. However, we do end up auto-boxing the int to be able to call BoxesRunTime.unboxToInt which does introduce boxing. This is unfortunate, although there is some chance that if the unboxToInt method gets inlined, that Hotspot might optimize it away. (I have no evidence either way; it would be better if this call was not emitted by scalac.)

spex$mIc$sp

This method exists to show how we'd like for spec$mIc$sp to be compiled. Logically they have the same signature, but this one just returns the int it was given, which will be easily inlined and should be suitable for basically any purpose.

conclusion

I don't think there's any way that using singletons in generic, non-specialized code can avoid boxing. I do think that the erased form of ValueOf should work correctly with respect to specialization and I think we are relatively close to having that working.

It would be nice if A <: Int implied specialization and/or never generated any Java code that mentioned Object. I'm uncertain how hard it would be to achieve this but will give it some more thought.

Compiled from "tlc.scala"
public class tlc.Demo {
public int concrete();
Code:
0: getstatic #16 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: new #18 // class scala/ValueOf
6: dup
7: iconst_1
8: invokestatic #24 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
11: checkcast #26 // class java/lang/Integer
14: invokespecial #30 // Method scala/ValueOf."<init>":(Ljava/lang/Object;)V
17: invokevirtual #34 // Method scala/Predef$.implicitly:(Ljava/lang/Object;)Ljava/lang/Object;
20: checkcast #18 // class scala/ValueOf
23: invokevirtual #38 // Method scala/ValueOf.value:()Ljava/lang/Object;
26: invokestatic #42 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
29: ireturn
public <A> A generic(A);
Code:
0: aload_1
1: areturn
public <A> A spec(A);
Code:
0: aload_1
1: areturn
public <A> A spex(A);
Code:
0: aload_1
1: areturn
public int spec$mIc$sp(int);
Code:
0: aload_1
1: invokestatic #42 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
4: ireturn
public int spex$mIc$sp(int);
Code:
0: iload_1
1: ireturn
public tlc.Demo();
Code:
0: aload_0
1: invokespecial #59 // Method java/lang/Object."<init>":()V
4: return
}
package tlc
class Demo {
def concrete: Int = implicitly[ValueOf[1]].value
def generic[A](implicit v: ValueOf[A]): A = v.value
def spec[@specialized(Int) A](implicit v: ValueOf[A]): A = v.value
def spex[@specialized(Int) A](implicit a: A): A = a
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment