Reputation: 2738
This seems like a minor issue since there is a simple work-around, but what is the difference between these two expressions?
List(1, 2, 3).sortBy(_)
List(1, 2, 3).sortBy(x => x)
The first gets a compiler diagnostic
missing parameter type for expanded function ((x$1) => List(1, 2, 3).sortBy(x$1))
The second is treated as syntactically valid.
Thanks.
Upvotes: 2
Views: 340
Reputation: 1470
I think part of the confusion is that an underscore can mean many things in Scala. Among the many things it can mean are:
The Scala compiler is interpreting your first example as a partially applied function. Since there is no function to pass function parameters into, it is instead treating the underscore as a partially applied function:
scala> def opposite1(x: Int): Int = -x
opposite1: (x: Int)Int
scala> def opposite2: Int => Int = (x: Int) => -x // means the same as opposite1
opposite2: Int => Int
scala> def transform(x: Int, f: Int => Int): Int = f(x)
transform: (x: Int, f: Int => Int)Int
scala> transform(2, opposite2)
res6: Int = -2
So, transform
is a function that takes an Int and a function that takes an Int and returns an Int. I can partially apply the function by passing in just one of the paramters, but the problem is that the compilier doesn't try to do any type inference:
scala> transform(_, opposite2)
<console>:10: error: missing parameter type for expanded function
((x$1) => transform(x$1, opposite2))
transform(_, opposite2)
I can fix this by providing an explicit type declaration:
scala> transform(_: Int, opposite2)
res8: Int => Int = <function1>
scala> transform(2, _: Int => Int)
res9: (Int => Int) => Int = <function1>
In the case of your original example, it will compile if I provide a type declaration:
scala> List(1,2,3).sortBy(_: Int => Int)
res10: (Int => Int) => List[Int] = <function1>
So, res10 is a function that takes a single argument: a function that takes an Int and returns an Int, and the return type of res10 is a List[Int] that contains 1, 2 & 3:
scala> res10(opposite2)
res11: List[Int] = List(3, 2, 1)
Scala type inference is a very cool feature because it eliminates boiler plate code. HOWEVER, there are cases when the cost of typing a few extra characters to explicitly declare the type is well worth the investment.
Upvotes: 0
Reputation: 21567
The second one is simpler, it's just an identity function, which can be easily replace with identity
:
List(1, 2, 3).sortBy(x => x)
You're basically asking Scala take an element from the list, apply a function f
to it and sort the list with this results. It has the following signature:
def sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): List[A]
The first one is a syntactic sugar for lambda (anonymous) function. In your example it doesn't work because of the desugaring rules, it resolves to the closes enclosing scope, this is written in the error message:
((x$1) => List(1, 2, 3).sortBy(x$1))
To make this work you can do like this:
def f[T](a: T) = a
List(1, 2, 3).sortBy(f(_))
This won't throw a compilation error, cause the compile will desugar it into:
List(1, 2, 3).sortBy((x$1) => f(x$1))
Or you can just write
List(1, 2, 3).sortBy(identity)
Where identity is identical to f
function, it's defined in Predef.scala
Upvotes: 4