For following scala code when I set a debug point at if statement and enable "Log: Breakpoint hit message"
object App1 {
def main(args: Array[String]): Unit = {
iftest()
}
def iftest(): Unit = {
val setA: Set[String] = Set("a", "b", "c");
var setB: Set[String] = Set("d", "e", "f")
if(setA.size > setB.size){ //here break point at line 8
println("bigger")
}
}
}
I got the following output in console. The question is why this breakpoint is hit twice?
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
But for following similar Java code, the breakpoint is hit only once.
Set<String> set1 = new HashSet<>();
set1.add("1");
set1.add("2");
Set<String> set2 = new HashSet<>();
set2.add("a");
set2.add("b");
if(set1.size() > set2.size()){ //here break point at line 8
System.out.println("size different");
}
I got the following output
Breakpoint reached at com.eguller.JApp.main(JApp.java:8)
Is it a bug in Intellij debugger, or is it a feature of Scala programming language?
IntelliJ IDEA 2021.3 Java - 11 Scala - 2.12.15
CodePudding user response:
This is a peculiarity of scalac bytecode generation. For some reason it generates an additional position for the debugger just before the return instruction and puts it on that line. You may invoke "Show bytecode" action in the IDE and see that there are 2 LINENUMBER 8
entries:
// access flags 0x1
public iftest()V
L0
LINENUMBER 6 L0
GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
INVOKEVIRTUAL scala/Predef$.Set ()Lscala/collection/immutable/Set$;
GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
ICONST_3
ANEWARRAY java/lang/String
DUP
ICONST_0
LDC "a"
AASTORE
DUP
ICONST_1
LDC "b"
AASTORE
DUP
ICONST_2
LDC "c"
AASTORE
CHECKCAST [Ljava/lang/Object;
INVOKEVIRTUAL scala/runtime/ScalaRunTime$.wrapRefArray ([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
INVOKEVIRTUAL scala/collection/immutable/Set$.apply (Lscala/collection/immutable/Seq;)Ljava/lang/Object;
CHECKCAST scala/collection/immutable/Set
ASTORE 1
L1
LINENUMBER 7 L1
GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
INVOKEVIRTUAL scala/Predef$.Set ()Lscala/collection/immutable/Set$;
GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
ICONST_3
ANEWARRAY java/lang/String
DUP
ICONST_0
LDC "d"
AASTORE
DUP
ICONST_1
LDC "e"
AASTORE
DUP
ICONST_2
LDC "f"
AASTORE
CHECKCAST [Ljava/lang/Object;
INVOKEVIRTUAL scala/runtime/ScalaRunTime$.wrapRefArray ([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
INVOKEVIRTUAL scala/collection/immutable/Set$.apply (Lscala/collection/immutable/Seq;)Ljava/lang/Object;
CHECKCAST scala/collection/immutable/Set
ASTORE 2
L2
LINENUMBER 8 L2
ALOAD 1
INVOKEINTERFACE scala/collection/immutable/Set.size ()I (itf)
ALOAD 2
INVOKEINTERFACE scala/collection/immutable/Set.size ()I (itf)
IF_ICMPLE L3
L4
LINENUMBER 9 L4
GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
LDC "bigger"
INVOKEVIRTUAL scala/Predef$.println (Ljava/lang/Object;)V
GOTO L3
L3
LINENUMBER 8 L3
FRAME APPEND [scala/collection/immutable/Set scala/collection/immutable/Set]
RETURN
L5
LOCALVARIABLE setA Lscala/collection/immutable/Set; L1 L3 1
LOCALVARIABLE setB Lscala/collection/immutable/Set; L2 L3 2
LOCALVARIABLE this LApp1$; L0 L5 0
MAXSTACK = 6
MAXLOCALS = 3
Scala 3 compiler doesn't add this and breakpoints work as expected.