Monday, 18 June 2012

scala.Either

Even newcomers to Scala know about Option class. We are starting from it as from solution to Nullpointer errors, later we finding it as a very useful Monad implementation. It is dual natured - one is Monadic Container - value is inside - and second is Monadic Zero with no value. Actually sometimes it is useful to have some value even in Zero container. For example non breaking error handing. Errors are important and even can be accumulated into the List.

Either

There is an embedded into language solution for above issue: scala.Either. "Represents a value of one of two possible types (a disjoint union.) Instances of Either are either an instance of Left or Right."
The difference to Option is simple: both implementations (Left and Right)  incapsulates a value. Conventions for this is: Right is for result and Left contains error. Here is example taken from the official documentation (reworked to show Error Handling):

def parseInt(in: String): Either[String, Int] = try {
Right(in.toInt)
} catch {
case e: Exception =>
Left(e.getMessage)
}
def getStatus(res: Either[String, Int]) = res match {
case Right(x) => "You passed me : " + x
case Left(x) => "I can't recognise your number: " + x
}
view raw parseInt.scala hosted with ❤ by GitHub
1. Pattern Matching :
val in = Console.readLine("Type Either a string or an Int: ")
println(getStatus(parseInt(in)))
view raw use.scala hosted with ❤ by GitHub
2. Additionally to pattern matching value can be tested via isLeft or is Right methods. 3. Fold:
val in = Console.readLine("Type Either a string or an Int: ")
def leftFunc(em: String) = println("Error: " + em)
def rightFunc(i: Int) = println(i + " was calculated")
parseInt(in) fold(leftFunc _, rightFunc _)
view raw fold.scala hosted with ❤ by GitHub
4. A projection:
val l: Either[String, Int] = Left("String")
val r: Either[String, Int] = Right(6)
l.left.map(_.size): Either[Int, Int] // Left(6)
r.left.map(_.size): Either[Int, Int] // Right(12)
l.right.map(_.toDouble): Either[String, Double] // Left("String")
r.right.map(_.toDouble): Either[String, Double] // Right(12.0)
5. For-comprehension (via flatMap):
for (s <- l.left) yield s.size // Left(6)
view raw for.scala hosted with ❤ by GitHub


No comments:

Post a Comment