ftw
ftw

Reputation: 385

Scala: why works foo(1,2) and foo((1,2)) the same?

Say I have a Scala function :

def func(x:(Int,Int)):Int = x._1 + x._2

    func((1,2))  // This works as expected

But how come below function call also works correctly?

 func(1,2)

I know about function call being turned to object with apply methods but I am unable to see even then how this works?

Upvotes: 2

Views: 113

Answers (2)

The_Tourist
The_Tourist

Reputation: 2128

If there are no appropriate multi-argument methods and a single appropriate one-argument method, the Scala compiler will try to convert those comma separated arguments into tuples.

The type of the argument x to your func method is (Int, Int), which is a syntactic sugar for Tuple2[Int, Int]. So the signature of func method is actually func(Tuple2[Int, Int]).

You invoke it as func(1, 2), but there's no method with signature func(Int, Int) defined in the scope, so the compiler will roughly translate the invocation to func(Tuple2(1, 2)), which matches the signature of your method. So this kind of invocation will work, but can lead to unexpected results (it's not hard to see why).

EDIT: Also see this question for additional reading.

Upvotes: 2

chengpohi
chengpohi

Reputation: 14217

This is a syntax of scala:

(x_1 , … , x_n),((x_1 , … , x_n))is a shorthand for `Tuple$n$($x_1 , … , x_n$)

check this Tuples, revised.

and also when check the generated bytecode:

scala> def bar(x: Int, y: Int) = func(x, y)
scala> :javap -c bar
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 #23                 // Method "<init>":()V
       6: return

  public int bar(int, int);
    Code:
       0: getstatic     #30                 // Field $line3/$read$$iw$$iw$.MODULE$:L$line3/$read$$iw$$iw$;
       3: new           #32                 // class scala/Tuple2$mcII$sp
       6: dup
       7: iload_1
       8: iload_2
       9: invokespecial #35                 // Method scala/Tuple2$mcII$sp."<init>":(II)V
      12: invokevirtual #39                 // Method $line3/$read$$iw$$iw$.func:(Lscala/Tuple2;)I
      15: ireturn

  public $line5.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #42                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #44                 // Field MODULE$:L$line5/$read$$iw$$iw$;
       8: return
}

we can see this is transformed by compiler: new #32 // class scala/Tuple2$mcII$sp

and I think this is equivalent to Function.untupled, example:

scala> Function.untupled(func _)(1, 2)
res1: Int = 3

Upvotes: 0

Related Questions