The underscores are really only syntactic sugar.
Person(_, _) is directly translated to
(a, b) => Person(a, b), just with generated names for the parameters, so both are totally the same. It actually happens before any typechecks whatsoever (you can check with
scalac -Xshow-phases, which will list phase 1 as
parse source into ASTs, perform simple desugaring, while typing is phase 4).
So the type inference has to happen in both cases, as both do not give types for the function parameters. The inference always goes from left to right, per parameter list. This is important, having both parameters to
map2 in the same parameter list would reduce the compiler’s ability to infer types and we may have to specify them for the function.
With the multiple parameter lists, it works like @jducoeur says, the compiler looks at the first parameter list, with expects an
Either[EE, B] and the Parameter we give it is an
Either[String, Age]. So
B is definitely fixed.
EE, the compiler will look if
String is a supertype of
mkName) is also
String, so no problem. If it wasn’t, the compiler would then look for the narrowest type, that is both a supertype of
Now we know
A was already set to
Name from the Either we call
map2 on, so only
C is left. This means, all types for the input to our function are known. The return type
C can be inferred from the body of the function, the last expression is of type
Person, so that’s what
I don’t feel like this is pushing inference hard, most higher-order functions use this. I rarely see lambdas with specified parameter types.
To better remember how the underscore syntax works, you can compare it with a fill-in-the-blanks text: you give an expression with blanks
_ and the compiler fills them with parameters from left to right, one parameter per blank.