12

I'm a bit shaky on the rules as to when you need a _ after a method to use it as a function. For example, why is there a difference between Foo's and Nil's :: in the following?

def square(n: Int) = n * n  
object Foo { def ::(f: Int => Int) = f(42) }

// ...

scala> Foo.::(square)
res2: Int = 1764

scala> Nil.::(square) 
<console>:6: error: missing arguments for method square in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
   Nil.::(square)
          ^
scala> Nil.::(square _) 
res3: List[(Int) => Int] = List(<function1>)
hammar
  • 138,522
  • 17
  • 304
  • 385
Matt R
  • 9,892
  • 10
  • 50
  • 83

1 Answers1

15

When you omit all parameters in a partially applied function expression, then you need to follow it with _ unless the compiler requires a function type in the place where you use it.

When you call the method :: on Foo, the compiler expects a type Int => Int for the parameter. So you can safely omit the underscore after square in that position.

However, the :: method on Nil can take a parameter of any type. So rather than assume that you meant to partially apply the function, it complains unless you make it absolutely explicit by adding _.

So those are the rules... I can't really enlighten you about why those are the rules; maybe somebody else who has better knowledge of the compiler, the type system, and the language design will be able to tell you why. But I assume that without these rules, there would be a danger of accidental ambiguity in many places.

Ben James
  • 121,135
  • 26
  • 193
  • 155
  • 2
    Thanks. Just found part of the Scala Language Spec which gives some justification for the "why", in the change notes for Scala 2.0: "The rules for implicit conversions of methods to functions (§6.25) have been tightened. Previously, a parameterized method used as a value was always implicitly converted to a function. This could lead to unexpected results when method arguments where forgotten. Consider for instance the statement below: show(x.toString)..." – Matt R Jan 14 '10 at 14:43