Ugliness of implementing Floyd-Warshall in Scala

Hmm, I thought that it wouldn’t be optimized by the compiler, but running following code though Scala 2.12.10:

object TupleNoOpMatch {
  def main(args: Array[String]): Unit = {
    (1, 2, 3) match {
      case (_, _, _) =>
        println("Hello, world!")
    }
  }
}

and decompiling it using javap shows:

Compiled from "TupleNoOpMatch.scala"
public final class patmat.TupleNoOpMatch$ {
  public static patmat.TupleNoOpMatch$ MODULE$;
    descriptor: Lpatmat/TupleNoOpMatch$;

  public static {};
    descriptor: ()V
    Code:
       0: new           #2                  // class patmat/TupleNoOpMatch$
       3: invokespecial #12                 // Method "<init>":()V
       6: return

  public void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    Code:
      // tuple creation
       0: new           #17                 // class scala/Tuple3
       3: dup
       4: iconst_1
       5: invokestatic  #23                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
       8: iconst_2
       9: invokestatic  #23                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
      12: iconst_3
      13: invokestatic  #23                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
      16: invokespecial #26                 // Method scala/Tuple3."<init>":(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
      19: astore_3
      // pattern matching without deconstruction
      20: aload_3
      // curiously null check survived the optimizations, but deconstruction didn't
      21: ifnull        39
      24: getstatic     #31                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
      27: ldc           #33                 // String Hello, world!
      29: invokevirtual #37                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
      32: getstatic     #43                 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
      35: astore_2
      36: goto          51
      39: goto          42
      42: new           #45                 // class scala/MatchError
      45: dup
      46: aload_3
      47: invokespecial #47                 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
      50: athrow
      51: return

  private patmat.TupleNoOpMatch$();
    descriptor: ()V
    Code:
       0: aload_0
       1: invokespecial #51                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #53                 // Field MODULE$:Lpatmat/TupleNoOpMatch$;
       8: return
}

therefore it seems it’s only style issue.

1 Like

Probably it isn’t. It’s something I’ve just came up with, not something I could find in standard library. I think libraries like scalaz should have cartesian products built in, but I’m not using scalaz on daily basis.

The bytecode optimizer (blog post here) handles tuple construction and deconstruction, you can enable it with -opt:l:method. This flag can safely be used, it just slows down compilation. (The inliner needs to be enabled more carefully, as explained in the blog post.)

$> cat Test.scala

object TupleNoOpMatch {
  def main(args: Array[String]): Unit = {
    (1, 2, 3) match {
      case (_, _, _) =>
        println("Hello, world!")
    }
  }
}

$> scalac12 Test.scala -opt:l:method

$> cfr-decompiler TupleNoOpMatch\$.class

public final class TupleNoOpMatch$ {
    public void main(String[] args) {
        Predef$.MODULE$.println((Object)"Hello, world!");
    }
}
1 Like