3

I don't understand why scala needs me to sometimes name args to anon fns:

scala> case class Person(name: String)
defined class Person

scala> def reverseString(s: String) = s.reverse
reverseString: (s: String)String

scala> val p = Some(Person("foo"))
p: Some[Person] = Some(Person(foo))

scala> p map { reverseString(_.name) }
<console>:12: error: missing parameter type for expanded function ((x$1) => x$1.name)
              p map { reverseString(_.name) }

// why does it only work when I name the argument? I'm not even telling it the type.
scala> p map { p => reverseString(p.name) }
res9: Option[String] = Some(oof)

// and shouldn't this fail too?
scala> p map { _.name.reverse }
res13: Option[String] = Some(oof)
devth
  • 2,738
  • 4
  • 31
  • 51
  • possible duplicate of [What are the rules to govern underscore to define anonymous function?](http://stackoverflow.com/questions/28125850/what-are-the-rules-to-govern-underscore-to-define-anonymous-function) – Suma Jan 25 '15 at 14:39

2 Answers2

4

The answer is in the error message, but cryptically so:

(x$1) => x$1.name

Wait, what? You wanted x$1 => reverseString(x$1.name).

So now you see exactly what went wrong: it assumed the function was inside the reverseString parens (i.e. you wanted to pass a function to reverseString). By explicitly naming the variable, you demonstrate to it that it was mistaken.

(It gives that message because once it assumes that reverseString should be passed a function, it doesn't know what type to make that function since reverseString actually wants a string, not a function.)

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • So why doesn't it just expand to `x$1 => reverseString(x$1.name)` in the first place? In this example: `val double = (x: Int) => x * 2; val doubled = 1 to 5 map { double(_) }` wouldn't `_` be expanding as `(Int => Int)` and failing, because `double` requires an `Int`? – devth Oct 05 '12 at 18:47
  • 1
    @devth - No, because `_` alone as an argument means "partially apply" (i.e. create a function out of this method, taking any unsupplied arguments as parameters), and a partially applied function (with the whole argument list) is just that function. Do anything more complicated, like `double(_*2)` and it will fail for the same reason. – Rex Kerr Oct 05 '12 at 18:49
  • Ah, that makes sense. So regarding my other question - why doesn't Scala expand to the more sensible `x$1 => reverseString(x$2.name)`? Is there a case where this would be a bad assumption? – devth Oct 05 '12 at 18:54
  • @devth - I think it's more a factor of compilation already being slow, and the specification documentation and code required being nontrivial (especially when you consider multiple nestings, and how many is too many for the programmer to keep track of), than that there are cases where it's a bad assumption. At some point rather than computing increasingly wild speculative branches, it's better to just ask the programmer to clarify. – Rex Kerr Oct 05 '12 at 19:20
0

I believe this is what is referred to as Type Inference. Also, _ is just a placeholder. (You already defined p as type Some[Person] so the compiler is smart enough to figure that out when used the way you did)

Jordan Denison
  • 2,649
  • 14
  • 14