13

scala coalesces multiple function call parameters into a Tuple -- can this be disabled? discusses Scala creating a tuple to bind to one arg function. This results in

scala> println(1, 2)
(1,2)

The answer says that the compiler allows one arg functions to be called with no parens, so that logically this is a call to println with a tuple.

But println cannot be called with a single tuple parameter

scala> val t = (1, 2)
t: (Int, Int) = (1,2)

scala> println t
<console>:6: error: value t is not a member of Unit
       println t
           ^

so something else is going on. Why are tuples special here?

Community
  • 1
  • 1
Duncan McGregor
  • 17,665
  • 12
  • 64
  • 118

2 Answers2

16

Contrary to this explanation, Scala parses println(1,2) (or Console println (1,2) for that matter) the same way it parses any two-argument method call. Later, the compiler transforms the call by wrapping the method arguments in a tuple to match the actual method type signature.

If the compiler did not do this, perfectly valid expressions like Console println (1,2) would fail to compile because println does not take multiple arguments. There are also other valid use cases for this behavior.

Consider an expression like foo bar (1,2) from the compiler's point of view, keeping in mind that Scala has special syntax that allows you to drop the . and the parens on method calls. This could be a call to a two-argument bar method with arguments 1 and 2, or it could be a call to a one-argument bar method with a single tuple-valued argument. The parser doesn't know anything about the bar method, so it just parses as a two-argument method call.

During the type checking phase, suppose the compiler determines that foo has no two-argument bar method but that it does have a one-argument bar method whose signature is compatible with the tuple interpretation. Since there is no other valid interpretation, it assumes that this is what you meant and transforms the two arguments into a tuple. Note that if there is a two-argument bar method, even one that is incompatible with the actual arguments, the typer will not perform the auto-tupling transformation.

Community
  • 1
  • 1
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
  • So as I understand your answer, the compiler is not using the no-parens case, but rather the parens case with later transformation of a list of args to a tuple in order to match `println(o: Any)` – Duncan McGregor May 14 '11 at 08:06
  • And further that the transformation to a tuple is there to allow the writing of functions that take variable arguments. – Duncan McGregor May 14 '11 at 08:10
  • No, variable arguments are unrelated. I'll edit the answer to make it more clear. – Aaron Novstrup May 14 '11 at 17:05
  • 1
    Rather than variable arguments I should have said function of any arity, and rather than writing them, what, manipulating them? – Duncan McGregor May 14 '11 at 20:09
0

A statement, that you can omit parens when calling on-arg function is not always true. Note, that:

    println "hello"
    val puts = (s: String) => println(s)
    puts "hello"

don't work either, despite that there's no tuple here. It works if you use infix notation. Following statements work great:

    Console println "hello"
    val t = (1, 2)
    Console println t
    puts apply "hello" // puts is defined above
Przemek Pokrywka
  • 2,219
  • 17
  • 23
  • I was a little surprised when I discovered that I can only omit parens when using infix too, as it seems to make some DSLs a little stilted eg `result should equal(42)` but I guess that the parser may need a little help. But this still doesn't explain how the tuple is being bound... – Duncan McGregor May 13 '11 at 21:34