Certain things were confusing me even after reading Jatin's answer. Here are my findings after some further research. Note, to save typing, am not using Type ascriptions on left hand side and let Scala infer stuff.
def f1(n: String, m: String): String = m + n
// f1: (n: String, m: String)String
val f2 = f1(_, "something")
Generally, underscores in an "expression" represent anonymous functions which are expanded appropriately by the compiler. If the compiler can not find a suitable type for the 'underscore' parameter, it will complain like below:
// <console>:12: error: missing parameter type for expanded function ((x$1) => f1(x$1, "something"))
val f2 = f1(_:String, "something") // Specifiying the type of the `_` as `_:String` fixes the missing parameter type error above.
// f2: String => String = <function1>
val r1 = f2 -> "foo"
// r1: (String => String, String) = (<function1>,foo)
Now the important stuff. Why does not the below line give the same result as r1 above!!! The reason lies in excellent answer by Daniel at underscore scoping rules.
val r2 = f1(_:String, "something") -> "foo"
// r2: String => (String, String) = <function1>
According to the 1st rule in the answer by Daniel, the scope of the anonymous function will include the whole right side expression. So the expanded anonymous function above will be
(x:String) => f1(x:String, "something") -> "foo"
Which gives the function signature String => (String, String)
In order to fix that, we use the 2nd rule in Sobral's answer and limit the scope of the anonymous function bound to the _
by enclosing the f1
expression with () or {}, like below:
val r3 = (f1(_:String, "something")) -> "foo"
r3: (String => String, String) = (<function1>,foo)
Now, we get the same result as val r1 = f2 -> "foo"