8

Let's declare a def and an equivalent function as a val:

scala> def optional(x:Int):Option[String] = None
optional: (x: Int)Option[String]

scala> val optional2:(Int)=>Option[String] = (i:Int) => None
optional2: Int => Option[String] = <function1>

Now why doesn't this work?

scala> List(1).flatMap(optional2)
<console>:9: error: type mismatch;
 found   : Int => Option[String]
 required: Int => scala.collection.GenTraversableOnce[?]
              List(1).flatMap(optional2)
                              ^

While both of these do?

scala> List(1).flatMap(optional)
res4: List[String] = List()

scala> List(1).flatMap(optional2(_))
res5: List[String] = List()

Since Option is not a subtype of GenTraversableOnce, I think this must have something to do with implicits, but I can't figure out what exactly it is. I am using Scala 2.9.1.

Artemis
  • 2,553
  • 7
  • 21
  • 36
Kim Stebel
  • 41,826
  • 12
  • 125
  • 142

1 Answers1

7

The implicit conversion Option.option2Iterable is what makes List(1).flatMap(optional) and List(1).flatMap(optional2(_)) work.

Your issue can be boiled down to the implicit conversion not being picked up:

scala> val optional2:(Int)=>Option[String] = (i:Int) => None
optional2: Int => Option[String] = <function1>

scala> (optional2(_)): Function[Int, Iterable[String]]
res0: Int => Iterable[String] = <function1>

scala> (optional2): Function[Int, Iterable[String]]
<console>:9: error: type mismatch;
 found   : Int => Option[String]
 required: Int => Iterable[String]

When you use the underscore, the compiler attempts to type the function and provide the necessary implicit conversion. When you just provide optional2, there is no implicit conversion that applies.

huynhjl
  • 41,520
  • 14
  • 105
  • 158
  • yeah, but why can't it be applied in the first case? – Kim Stebel Mar 18 '12 at 19:08
  • @KimStebel, there is no implicit conversion for `optional2`. In the second case `optional2(_)`, the compiler builds a function for you and attempts to match the return type and that's when it chooses `option2Iterable`. – huynhjl Mar 18 '12 at 19:27
  • 3
    In other words, there's no implicit conversion from `Function[T,R1] => Function[T,R2]` where an implicit `R1 => R2` exists. You need to build a new function object with `optional2(_)` so that the implicit conversion can occur, in this case `i => optional2(i: Iterable[String])`. `optional2` is one object, `optional2(_)` is a new one. – Luigi Plinge Mar 18 '12 at 19:42