I am using _
as placeholder for creating anonymous function, and the problem is I cannot predict how Scala is going to transform my code. More precisely, it mistakenly determines how "large" the anonymous function I want.
List(1,2,3) foreach println(_:Int) //error !
List(1,2,3) foreach (println(_:Int)) //work
List(1,2,3) foreach(println(_:Int)) //work
Using -Xprint:typer
I can see Scala transforms the first one into "a big anonymous function":
x$1 => List(1,2,3) foreach(println(x$1:Int))
the worked 2th 3th are right transformation into what I want.
... foreach (x$1 => println(x$1:Int))
Why this? What's the rule ?
I believe Mr. Sobral's answer is incorrect. The actual rules can be found in Scala Language Reference, section 6.23, subhead "Placeholder Syntax for Anonymous Functions."
The only rule is that the innermost expression that properly contains the underscore defines the scope of the anonymous function. That means that Mr. Sobral's first two rules are correct, because a method call is an expression and parenthesizing an expression doesn't change its meaning. But the third rule is the opposite of the truth: all other things being equal, the smallest expression that makes sense will be used.
Unfortunately, my explanation for the behavior Mr. Laskowski observed for his first example is a bit involved and speculative. When
is typed at the Scala read-eval-print loop. The error message is:
If you vary the example a tiny bit:
the error message is easier to make sense of --
To understand things a little better, call
scala
thus:scala -Xprint:parser
, which, after every expression is typed by the user, causes the expression as fleshed out by the parser to be printed. (Along with a lot of garbage, which I'll omit.) For Laskowski's first example, the expression understood by the parser isFor the second example, the parser's version is
Apparently the scope rule is applied before the expression structure has been fully fleshed out. In both cases, the parser guesses that the smallest expression starts at List, even though once the parens are inserted that's no longer true. In the second example, in addition to that assumption it assumes that, because
println
is an identifier,foreach println
is a chain of methods, the first having no arguments. The error atforeach
is then caught before the error atprintln
, masking it. The error atprintln
is that its result is Unit, andforeach
requires a function. Once you see the parse tree, it's easy to see that this is correct, but it's not clear (to me) why the parse tree is what it is.Simple rules to determine the scope of underscore:
So, by the rule #1, instead of
println((x: Int) => x)
, the scope will be placed outside (including)println
.By rule #2, the latter two examples will have the function delimited by parenthesis, so
(x => println(x: Int))
.By rule #3, the first example will be the whole expression, as there are no delimiting parenthesis.