Scala Option, Either, and Try: Functional Error Handling
Scala Option, Either, and Try: Functional Error Handling
Idiomatic Scala avoids null and exceptions for expected failure cases. Instead, it uses three powerful types: Option for values that may or may not exist, Either for operations that can fail with an error, and Try for wrapping code that might throw exceptions. This module covers all three.
Option: Replacing null
Option[A] has two subtypes:
Some(value)— contains a valueNone— represents absence of a value
def findUser(id: Int): Option[String] = {
val users = Map(1 -> "Alice", 2 -> "Bob")
users.get(id)
}
val user = findUser(1) // Some(Alice)
val missing = findUser(99) // None
// Pattern matching
user match {
case Some(name) => println(s"Found: $name")
case None => println("Not found")
}Chaining with map and flatMap
val upper: Option[String] = findUser(1).map(_.toUpperCase)
println(upper) // Some(ALICE)
val missing: Option[String] = findUser(99).map(_.toUpperCase)
println(missing) // None — map is a no-op on NonegetOrElse and fold
val name = findUser(1).getOrElse("Anonymous") // "Alice"
val missing = findUser(99).getOrElse("Anonymous") // "Anonymous"
// fold: combine the two cases in one call
val result = findUser(1).fold("Not found")(name => s"Hello, $name")
println(result) // Hello, AliceflatMap for chained lookups
def findDepartment(userId: Int): Option[String] =
Map(1 -> "Engineering", 2 -> "Marketing").get(userId)
val dept = findUser(1).flatMap(name => findDepartment(1))
println(dept) // Some(Engineering)Either: Typed Error Handling
Either[L, R] represents one of two possible values:
Left(error)— the failure case (by convention)Right(value)— the success case
def divide(a: Int, b: Int): Either[String, Double] =
if (b == 0) Left("Division by zero")
else Right(a.toDouble / b)
val result = divide(10, 2) // Right(5.0)
val error = divide(10, 0) // Left(Division by zero)
result match {
case Right(value) => println(s"Result: $value")
case Left(err) => println(s"Error: $err")
}Chaining Either with map and flatMap
Either is right-biased in Scala 2.12+ — map and flatMap operate on the Right value:
def parseAge(s: String): Either[String, Int] =
s.toIntOption match {
case Some(n) if n >= 0 && n <= 150 => Right(n)
case Some(_) => Left("Age out of range")
case None => Left(s"'$s' is not a number")
}
def validateUser(name: String, ageStr: String): Either[String, String] =
for {
age <- parseAge(ageStr)
validated <- if (name.nonEmpty) Right(s"$name, age $age") else Left("Name is empty")
} yield validated
println(validateUser("Alice", "30")) // Right(Alice, age 30)
println(validateUser("", "30")) // Left(Name is empty)
println(validateUser("Bob", "abc")) // Left('abc' is not a number)Try: Wrapping Exception-Throwing Code
Try[A] wraps code that might throw an exception:
Success(value)— computation succeededFailure(exception)— computation threw an exception
import scala.util.{Try, Success, Failure}
def parseNumber(s: String): Try[Int] = Try(s.toInt)
val good = parseNumber("42") // Success(42)
val bad = parseNumber("abc") // Failure(NumberFormatException)
good match {
case Success(n) => println(s"Parsed: $n")
case Failure(err) => println(s"Error: ${err.getMessage}")
}Converting between Try, Option, and Either
// Try to Option
val opt: Option[Int] = parseNumber("42").toOption // Some(42)
// Try to Either
val either: Either[Throwable, Int] = parseNumber("42").toEither // Right(42)
// Option to Either
val e: Either[String, Int] = findUser(1).toRight("User not found")Choosing Between Option, Either, and Try
| Type | Use When |
|---|---|
Option | A value may or may not exist; no error information needed |
Either | An operation can fail; you want a descriptive error type |
Try | Wrapping Java/library code that throws exceptions |
Frequently Asked Questions
Q: Is Option just Scala's version of Java's Optional?
They are similar but Option comes first — Java's Optional was introduced in Java 8 (2014), partly inspired by Scala's Option and similar types in functional languages. The key difference is that Scala's Option is deeply integrated with the language's type system, for-comprehensions, and collection operations, making it more composable.
Q: Why does Scala use Right for success in Either?
It's a convention — Right sounds like "right" (correct), and Left sounds like "what's left after the right answer failed". More practically, Scala's Either is right-biased: map, flatMap, and for-comprehensions all operate on the Right value. The convention aligns with the language's bias.
Q: When should I use Try vs Either?
Use Try when you're calling code that throws exceptions (especially Java library code) and want to catch all exceptions automatically. Use Either when you're writing your own error-handling logic with specific, typed error cases. Either[MyError, A] makes the error type explicit and lets callers handle different errors differently — Try[A] just captures Throwable.
Part of Scala Mastery Course — Module 11 of 22.
