I am learning Scala and have a very basic question. Consider the following two expressions using the placeholder syntax -
// Syntax A
val fnA = (_: Int, _: Int) => _ / _
// Syntax B
val fnB = (_: Int) / (_: Int)
and their attempted applications -
// Syntax A
fnA(33, 3)
// Syntax B
fnB(33, 3)
Out of these two, only B and App(B) are valid syntax and I am not sure why. If the compiler is able to infer the arguments (and the order to apply them in) in fnB
why is it not able to do it for fnA
? I am basing my question on the premise that fnB
is a shorthand for fnA
and I am pretty certain there's a flaw in that reasoning. I am just not sure what the flaw is.
The meaning of underscores on the left of arrow =>
(_: Int, _: Int) => ...
are different from the meaning of underscores around the infix operator /
(_: Int) / (_: Int)
The former mean something like
"We are defining a function that takes two arguments, however we will not use these arguments in the body of the function"
whilst the latter is a shorthand for defining a function of two arguments
(x: Int, y: Int) => x / y
For example,
(_: Int, _: Int) => (_: Int) / (_: Int)
desugars to something like
(a: Int, b: Int) => ((x: Int, y: Int) => x / y)
where we see arguments a
and b
are not used in the body which happens to be yet another function ((x: Int, y: Int) => x / y)
.
Daniel documents the two meanings as
_ + _ // Anonymous function placeholder parameter
_ => 5 // Discarded parameter
As a side-note, consider a somewhat analogous situation at the typelevel involving type constructors and their bounds where the meaning of underscore depends on the context
CC[_] <: Iterable[_]
Personally, my mind tricks me to think it is equivalent to
CC[x] <: Iterable[x]
however that is not the case, and the meaning of the underscore on the left of <:
is different from the meaning on the right
CC[x] <: Iterable[y] forSome {type y}
Note how x
does not appear in Iterable[y] forSome {type y}
. Adrian documents this under Common Pitfalls:
...perhaps surprisingly,
CC[_] <: Traversable[_]
is not equivalent toCC[X] <: Traversable[X]
. The former expands toCC[X] <: Traversable[T] forSome {type T}
, whereT
is existentially bound and thus unrelated toX
.
and in a comment to type bounds on type constructor
comparing the level of types and values, it is quite unfortunate that the type-level underscore behaves differently from the value-level underscore. At the value level,
_ + _
indeed stands for(x, y) => x + y
, a function. As hinted at in my other comment, the type-level underscore is context-sensitive, and it never introduces a type-level function. It's either an anonymous type parameter definition or an anonymous existential. Neither of these have value-level equivalents.
Hence we should be careful to interpret the meaning of the underscore within its context.