Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I flatMap a Try?

Tags:

scala

Given

val strings = Set("Hi", "there", "friend")
def numberOfCharsDiv2(s: String) = scala.util.Try { 
  if (s.length % 2 == 0) s.length / 2 else throw new RuntimeException("grr") 
}

Why can't I flatMap away the Try resulting from the method call? i.e.

strings.flatMap(numberOfCharsDiv2)
<console>:10: error: type mismatch;
 found   : scala.util.Try[Int]
 required: scala.collection.GenTraversableOnce[?]
              strings.flatMap(numberOfCharsDiv2)

or

for {
  s <- strings
  n <- numberOfCharsDiv2(s)
} yield n
<console>:12: error: type mismatch;
 found   : scala.util.Try[Int]
 required: scala.collection.GenTraversableOnce[?]
            n <- numberOfCharsDiv2(s)

However if I use Option instead of Try there's no problem.

def numberOfCharsDiv2(s: String) = if (s.length % 2 == 0) 
  Some(s.length / 2) else None
strings.flatMap(numberOfCharsDiv2) # =>  Set(1, 3)

What's the rationale behind not allowing flatMap on Try?

like image 598
Synesso Avatar asked Aug 30 '14 14:08

Synesso


2 Answers

Kigyo explains well why Scala does not do this implicitly. To put it simply, Scala does not want to automatically throw away the exception that is preserved in a Try.

Scala does provide a simple way to explicitly translate a Try into an Option though. This is how you can use a Try in a flatmap:

strings.flatMap(numberOfCharsDiv2(_).toOption)
like image 82
Jack Davidson Avatar answered Oct 27 '22 08:10

Jack Davidson


It is a Monad in Scala 2.11:

scala> import scala.util._ 
import scala.util._

scala> val x: Try[String] = Success[String]("abc")
x: scala.util.Try[String] = Success(abc)

scala> val y: Try[String] = Failure[String](new Exception("oops"))
y: scala.util.Try[String] = Failure(java.lang.Exception: oops)

scala> val z = Try(x)
z: scala.util.Try[scala.util.Try[String]] = Success(Success(abc))

scala> val t = Try(y)
t: scala.util.Try[scala.util.Try[String]] = Success(Failure(java.lang.Exception: oops))

scala> z.flatten
res2: scala.util.Try[String] = Success(abc)

scala> t.flatten
res3: scala.util.Try[String] = 
Failure(java.lang.UnsupportedOperationException: oops)
like image 25
Vlad Patryshev Avatar answered Oct 27 '22 07:10

Vlad Patryshev