Skip to content

Verbose bytecode generated for the creation of a single tuple via -> #24715

@nmichael44

Description

@nmichael44

Compiler version

3.7.4

Minimized code

object PairProblem {
  def f0(x: Int, y: Int): (Int, Int) =
    val p = (x, y)

    p

  def f1(x: Int, y: Int): (Int, Int) =
    val p = x -> y

    p
}

Output

Naively I assumed the code produced by the two functions above would be identical but alas it's not.
For f0 we get what one would expect. But f1 looks quite different. First, the first integer is boxed, we then create
an instance of class ArrowAssoc, then box the other integer, and finally call the -> method on object we created. So we build 4 objects, instead of 1 as the other method does. All in all 14 bytecode instructions vs 8.

The strange thing is that ArrowAssoc inherits from AnyVal and -> appears to be declared inline neither of
which appears to be doing anything (I show their defs below).

  public f0(II)Lscala/Tuple2;
    // parameter final  x
    // parameter final  y
   L0
    LINENUMBER 5 L0
    NEW scala/Tuple2$mcII$sp
    DUP
    ILOAD 1
    ILOAD 2
    INVOKESPECIAL scala/Tuple2$mcII$sp.<init> (II)V
    ASTORE 3
   L1
    LINENUMBER 7 L1
    ALOAD 3
    ARETURN
   L2
    LOCALVARIABLE p Lscala/Tuple2; L1 L2 3
    LOCALVARIABLE this Lneo/com/PairProblem$; L0 L2 0
    LOCALVARIABLE x I L0 L2 1
    LOCALVARIABLE y I L0 L2 2
    MAXSTACK = 4
    MAXLOCALS = 4

  // access flags 0x1
  // signature (II)Lscala/Tuple2<Ljava/lang/Object;Ljava/lang/Object;>;
  // declaration: scala.Tuple2<java.lang.Object, java.lang.Object> f1(int, int)
  public f1(II)Lscala/Tuple2;
    // parameter final  x
    // parameter final  y
   L0
    LINENUMBER 10 L0
    GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
    ILOAD 1
    INVOKESTATIC scala/runtime/BoxesRunTime.boxToInteger (I)Ljava/lang/Integer;
    INVOKEVIRTUAL scala/Predef$.ArrowAssoc (Ljava/lang/Object;)Ljava/lang/Object;
    CHECKCAST java/lang/Integer
    ASTORE 4
    GETSTATIC scala/Predef$ArrowAssoc$.MODULE$ : Lscala/Predef$ArrowAssoc$;
    ALOAD 4
    ILOAD 2
    INVOKESTATIC scala/runtime/BoxesRunTime.boxToInteger (I)Ljava/lang/Integer;
    INVOKEVIRTUAL scala/Predef$ArrowAssoc$.$minus$greater$extension (Ljava/lang/Object;Ljava/lang/Object;)Lscala/Tuple2;
    ASTORE 3
   L1
    LINENUMBER 12 L1
    ALOAD 3
    ARETURN
   L2
    LOCALVARIABLE p Lscala/Tuple2; L1 L2 3
    LOCALVARIABLE this Lneo/com/PairProblem$; L0 L2 0
    LOCALVARIABLE x I L0 L2 1
    LOCALVARIABLE y I L0 L2 2
    MAXSTACK = 3
    MAXLOCALS = 5

Here is the def of ArrowAssoc from the standard lib:

implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {
    @inline def -> [B](y: B): (A, B) = (self, y)
    @deprecated("Use `->` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.", "2.13.0")
    def [B](y: B): (A, B) = ->(y)
  }

Expectation

The code produced should be identical.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions