Search code examples
scalaimplicitscala-option

Methods versus Function and implicits in Scala


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.


Solution

  • 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.