8
votes

The following code doesn't compile:

def f[T](conv: Option[String => T]) {}
f(Some(_.toInt))

with <console>:13: error: missing parameter type for expanded function ((x$1) => x$1.toInt)

Of course, explicit type makes it fine:

scala> f(Some((x: String) => x.toInt))

Why the compiler can't infer String type here? Is there some kind of ambiguity?

In general, is it possible to check and examine manually the generated code from underscore expansion?

1
@slouc, post it as an asnwer - it's a correct one. If OP created some type classes that involved some variance or inheritance related to the String then it maybe would be able to infer it in some cases but otherwise you could just pass some ClassWithoutToInt and it cannot infer it with underscore, - sebszyller
@sebszyller I just deleted my comment because I think it's wrong :) how do you then explain the fact that if it weren't for the Option, that is, if method was only taking a function String => T, you could pass f(_.toInt) and it would work? - slouc
@slouc I don't know what your answer was, but hopefully mine explains why it would work. - Alexey Romanov
SO complains that don't boost enough questions. I agree that by common intuition, this should just work. Of course, I may be wrong for good reasons. - som-snytt
Use f(_.toInt) // show in REPL or -Xprint:typer to see how typer sees your code. - som-snytt

1 Answers

5
votes

The basic problem (I believe) is that when typing Some(_.toInt), the compiler needs to infer the type parameter of Some.apply[A](x: A), and to do that, it first needs to typecheck the arguments. So _.toInt is typechecked with A (considered as an unknown type constant) as expected type. This fails, because anonymous functions are only allowed not to specify parameter types when the expected type is a function type (or starting with Scala 2.12, a Single Abstract Method type). Then the compiler tries again with undefined as the expected type, and fails for the same reason.

In this case, the expected return type would actually be sufficient to determine the type parameter, and then this would allow to typecheck _.toInt, but that's not how it is designed to work.

The gory details, if you want them, are in http://scala-lang.org/files/archive/spec/2.11/06-expressions.html, paragraphs 6.6, 6.23, and 6.26.4.