Mahesh Chand
Mahesh Chand

Reputation: 3250

Different byte code generated issue

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

Answers (2)

som-snytt
som-snytt

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

Antimony
Antimony

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

Related Questions