Should the @switch annotation be ignored in classes that extend AnyVal? If so, why?
Scala Version: 2.12.9
Compiles to bytecode using TABLESWITCH:
import scala.annotation.switch
class SwitchTest(val value: Int) {
def test(a: Int): Int = (a: @switch) match {
case 1 => 1
case 2 => 2
case _ => -1
}
}
Does not compile to bytecode using TABLESWITCH:
import scala.annotation.switch
class SwitchTest(val value: Int) extends AnyVal {
def test(a: Int): Int = (a: @switch) match {
case 1 => 1
case 2 => 2
case _ => -1
}
}
I tested it again. This time in a new project (Intellij IDEA 2019.02.02 Ultimate, SBT 1.3.0) with nothing more than this test. Got the same result for Scala versions 2.13.1, 2.12.10, and 2.11.12 (using Java version OpenJDK 64-Bit Server VM, Java 1.8.0_222). The non-AnyVal compiles down to a TABLESWITCH operation while the AnyVal descendant compiles down to a series of conditionals.
Am I missing something??
Snippet below directly from the Scala 2.12 REPL:
$ scala
Welcome to Scala 2.12.10 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions for evaluation. Or try :help.
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.annotation.switch
class SwitchTest1(val value: Int) extends AnyVal {
def test(a: Int): Int = (a: @switch) match {
case 1 => 1
case 2 => 2
case _ => -1
}
}
class SwitchTest2(val value: Int) {
def test(a: Int): Int = (a: @switch) match {
case 1 => 1
case 2 => 2
case _ => -1
}
}
// Exiting paste mode, now interpreting.
import scala.annotation.switch
defined class SwitchTest1
defined class SwitchTest2
scala> :javap -c SwitchTest1
Compiled from "<console>"
public final class $line3.$read$$iw$$iw$SwitchTest1 {
public int value();
Code:
0: aload_0
1: getfield #21 // Field value:I
4: ireturn
public int test(int);
Code:
0: getstatic #30 // Field $line3/$read$$iw$$iw$SwitchTest1$.MODULE$:L$line3/$read$$iw$$iw$SwitchTest1$;
3: aload_0
4: invokevirtual #32 // Method value:()I
7: iload_1
8: invokevirtual #36 // Method $line3/$read$$iw$$iw$SwitchTest1$.test$extension:(II)I
11: ireturn
public int hashCode();
Code:
0: getstatic #30 // Field $line3/$read$$iw$$iw$SwitchTest1$.MODULE$:L$line3/$read$$iw$$iw$SwitchTest1$;
3: aload_0
4: invokevirtual #32 // Method value:()I
7: invokevirtual #40 // Method $line3/$read$$iw$$iw$SwitchTest1$.hashCode$extension:(I)I
10: ireturn
public boolean equals(java.lang.Object);
Code:
0: getstatic #30 // Field $line3/$read$$iw$$iw$SwitchTest1$.MODULE$:L$line3/$read$$iw$$iw$SwitchTest1$;
3: aload_0
4: invokevirtual #32 // Method value:()I
7: aload_1
8: invokevirtual #47 // Method $line3/$read$$iw$$iw$SwitchTest1$.equals$extension:(ILjava/lang/Object;)Z
11: ireturn
public $line3.$read$$iw$$iw$SwitchTest1(int);
Code:
0: aload_0
1: iload_1
2: putfield #21 // Field value:I
5: aload_0
6: invokespecial #53 // Method java/lang/Object."<init>":()V
9: return
}
scala> :javap -c SwitchTest2
Compiled from "<console>"
public class $line3.$read$$iw$$iw$SwitchTest2 {
public int value();
Code:
0: aload_0
1: getfield #18 // Field value:I
4: ireturn
public int test(int);
Code:
0: iload_1
1: istore_2
2: iload_2
3: tableswitch { // 1 to 2
1: 24
2: 28
default: 32
}
24: iconst_1
25: goto 36
28: iconst_2
29: goto 36
32: iconst_m1
33: goto 36
36: ireturn
public $line3.$read$$iw$$iw$SwitchTest2(int);
Code:
0: aload_0
1: iload_1
2: putfield #18 // Field value:I
5: aload_0
6: invokespecial #28 // Method java/lang/Object."<init>":()V
9: return
}
scala>
Thank you!! I was as confused by the difference and did not catch the references to the companion object. Learned something new. I appreciate your help.