2
def stringToIntMethod(input:String):Option[Int] = {
  try{
    Some(Integer.parseInt(input.trim()))
  }
  catch{
    case e:Exception => None
  }
}

val stringToIntFunction: (String) => Option[Int] = (in:String) => {
  try{
    Some(Integer.parseInt(in.trim()))
  }
  catch{
    case e:Exception => None
  }
}

val stringAndIntArray = Array("Hello", "1","2","Hi") //Input

println("with Method is: " + stringAndIntArray.flatMap(stringToIntMethod))
println("with functon is: " + stringAndIntArray.flatMap(stringToIntFunction))

getting a type mismatch error while using stringToIntFunction in flatMap

type mismatch;
  found   : String => Option[Int]
  required: String => scala.collection.GenTraversableOnce[?]
println("with functon is: " + stringAndIntArray.flatMap(stringToIntFunction))
                                                    ^

Why is it?

2 Answers 2

2

flatMap requires lambda, you are passing it a normal method

Here is the fix

stringAndIntArray.flatMap(stringToIntMethod _)

Scala REPL

scala> def toInt(s: String): Option[Int] = Some(s.toInt)
toInt: (s: String)Option[Int]

scala> Array("1", "2", "3").flatMap(toInt _)
res1: Array[Int] = Array(1, 2, 3)

Normal method can be converted to lambda using underscore

More examples for clarity

scala> def foo(s: String, i: Int): Double = 1
foo: (s: String, i: Int)Double

scala> foo _
res2: (String, Int) => Double = $$Lambda$1162/1477996447@62faf77

scala> foo(_, _)
res3: (String, Int) => Double = $$Lambda$1168/1373527802@30228de7


scala> foo(_: String, _: Int)
res5: (String, Int) => Double = $$Lambda$1183/477662472@2adc1e84


scala> foo("cow", _: Int)
res7: Int => Double = $$Lambda$1186/612641678@146add7b

scala> foo("Cow is holy", _: Int)
res8: Int => Double = $$Lambda$1187/1339440195@7d483ebe

Also adding a comment from lambda. xy. x

f _ is syntactic sugar for f(_) which is again syntactic sugar for x => f(x)
Sign up to request clarification or add additional context in comments.

6 Comments

Perhaps a small elaboration on the underscore: f _ is syntactic sugar for f(_) which is again syntactic sugar for x => f(x).
@lambda.xy.x Thanks for input!
Also that is called 'eta expansion' stackoverflow.com/questions/39445018/…
I want to use stringToIntFunction, not stringToIntMethod, even without _ or lambda conversation it works fine.
@Omprakash Yes, because its a lambda (function)
|
2

I'm still puzzled myself about why this example does not work. I assume it has to do with Scala's type inference. If you look at the error message

 found   : String => Option[Int]
 required: String => scala.collection.GenTraversableOnce[?]

it says that the return value of stringToIntFunction does not fit the argument value of flatMap. Indeed, the type test

Some(1).isInstanceOf[TraversableOnce[Int]]

leads to:

<console>:138: warning: fruitless type test: a value of type Some[Int] cannot also be a scala.collection.TraversableOnce[Int] (the underlying of TraversableOnce[Int])
  Some(1).isInstanceOf[TraversableOnce[Int]]
                      ^
res24: Boolean = false

Funnily enough, when I change the return type of your function toTraversableOnce[Int], it works:

def stringToIntFunction : String => TraversableOnce[Int] = (in:String) => {
   //...
}

leads to

scala> stringAndIntArray.flatMap(stringToIntFunction)
res28: Array[Int] = Array(1, 2)

The reason is that even though Option does not derive from TraversableOnce, there is an implicit conversion:

 scala> def f(to : TraversableOnce[Int]) = to.size
 f: (to: TraversableOnce[Int])Int
 scala> f(Some(1))
 res25: Int = 1

This has also been noticed in a different question before.

My theory is that for a method the return value is explicitly known to the compiler which allows it to detect the presence of an implicit conversion from Option[Int] => TraversableOnce[Int]. But in the case of a function value the compiler would only look for an implicit conversion between (String => Option[Int]) => (String => TraversableOnce[Int]). When the lambda application stringToIntFunction _ is passed instead, the compiler seems to see that it can apply the implicit conversion again.

2 Comments

Changing the return type to Traversable is not a good idea though because it contains an implicit conversion. Better directly return List(Integer.parseInt(in.trim())) then.
Yep, makes sense. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.