Reputation: 3250
I am trying to do a pattern match on the boolean value. I have written the same method with a slight modification but there is much difference in their bytecode generation.
For example
scala> def compare(flag: Boolean) = {
| flag match{
| case true => println("true..")
| case false => println("false...")
| }}
compare: (flag: Boolean)Unit
scala> :javap -c compare
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
public static $line4.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line4/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void compare(boolean);
Code:
0: iload_1
1: istore_3
2: iconst_1
3: iload_3
4: if_icmpne 22
7: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
10: ldc #27 // String true..
12: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
15: getstatic #37 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
18: astore_2
19: goto 60
22: goto 25
25: iconst_0
26: iload_3
27: if_icmpne 45
30: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
33: ldc #39 // String false...
35: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
38: getstatic #37 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
41: astore_2
42: goto 60
45: goto 48
48: new #41 // class scala/MatchError
51: dup
52: iload_3
53: invokestatic #47 // Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
56: invokespecial #49 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
59: athrow
60: return
public $line4.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #52 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #54 // Field MODULE$:L$line4/$read$$iw$$iw$;
8: return
}
When I do the same thing using if expression, there is different bytecode.
scala> def compareAgain(flag: Boolean) = {
| if(flag) println("true..")
| else println("false...")
| }
compareAgain: (flag: Boolean)Unit
scala> :javap -c compareAgain
Compiled from "<console>"
public class $line5.$read$$iw$$iw$ {
public static $line5.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line5/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void compareAgain(boolean);
Code:
0: iload_1
1: ifeq 15
4: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: ldc #27 // String true..
9: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
12: goto 23
15: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
18: ldc #33 // String false...
20: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
23: return
public $line5.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #36 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #38 // Field MODULE$:L$line5/$read$$iw$$iw$;
8: return
}
There is different bytecode. What does this mean in first bytecode?
// Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
Thanks in advance.
Upvotes: 3
Views: 130
Reputation: 39577
This is a duplicate of this question that was answered for the old pattern matcher and the old backend. Notice how life was simpler back then.
For the new and improved, you can get the code you want with an optimizer option. I don't know why they make you jump through hoops.
$ scala -opt:copy-propagation
Welcome to Scala 2.12.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
scala> def f(b: Boolean) = b match { case true => println() ; case _ => println() }
f: (b: Boolean)Unit
scala> :javap -c f
Compiled from "<console>"
public class $line3.$read$$iw$$iw$ {
public static $line3.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line3/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void f(boolean);
Code:
0: iconst_1
1: iload_1
2: if_icmpne 14
5: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
8: invokevirtual #28 // Method scala/Predef$.println:()V
11: goto 26
14: goto 17
17: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
20: invokevirtual #28 // Method scala/Predef$.println:()V
23: goto 26
26: return
public $line3.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #31 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #33 // Field MODULE$:L$line3/$read$$iw$$iw$;
8: return
}
Upvotes: 2
Reputation: 39461
Match expressions are just that, expressions. They evaluate to a value. In this case, you aren't using the value, but the compiler included the code anyway. Since println doesn't return anything useful, it evaluates to what's called the unit type, which is roughly equivalent to Void.
The match expression case also differs from the if else case in that if the argument is neither true nor false, a new MatchError is thrown. Of course, that case is unreachable unless you use custom bytecode to create a boolean with an unexpected value, but the compiler didn't try to optimize it away.
Upvotes: 2