Option, Either & Try

Either is right-biased: map/flatMap operate on Right.

16.1 Option — no nulls

def findUser(id: Int): Option[String] =
  if id == 1 then Some("Ann") else None

findUser(1).map(_.toUpperCase)             // Some("ANN")
findUser(2).getOrElse("unknown")           // "unknown"
findUser(1).fold("none")(n => s"found $n")
findUser(1).filter(_.startsWith("A"))
findUser(1).flatMap(n => findEmail(n))
findUser(1).foreach(println)
findUser(1).isDefined, findUser(2).isEmpty
findUser(2).orElse(Some("guest"))
findUser(1).contains("Ann"), findUser(1).exists(_.length > 2)
findUser(1).toList
Option(javaMethodThatMayReturnNull())      // wraps null as None

findUser(1) match
  case Some(name) => println(name)
  case None => println("not found")

16.2 Either — success or typed error

Either is right-biased: map/flatMap operate on Right.

enum AppError:
  case NotFound(id: Int)
  case Invalid(msg: String)

def parseAge(s: String): Either[AppError, Int] =
  s.toIntOption match
    case None => Left(AppError.Invalid(s"not a number: $s"))
    case Some(n) if n < 0 => Left(AppError.Invalid("negative"))
    case Some(n) => Right(n)

parseAge("42").map(_ + 1)                 // Right(43)
parseAge("x").left.map(_.toString)
parseAge("42").getOrElse(0)
parseAge("42").fold(err => s"error $err", age => s"age $age")
parseAge("42").toOption

16.3 Try — capturing exceptions

import scala.util.{Try, Success, Failure}

val result = Try("42".toInt)            // Success(42)
val bad = Try("x".toInt)                // Failure(NumberFormatException)

bad.getOrElse(0)
bad.recover { case _: NumberFormatException => -1 }
result.map(_ * 2).toOption
result.toEither
bad match
  case Success(v) => println(v)
  case Failure(e) => println(s"Error: ${e.getMessage}")

16.4 Chaining with for-comprehensions

def validate(name: String, ageStr: String): Either[AppError, User] =
  for
    age <- parseAge(ageStr)
    _ <- Either.cond(name.nonEmpty, (), AppError.Invalid("empty name"))
  yield User(name, s"[email protected]", age)

16.5 When to use which

value may be absent; absence needs no explanation Either[E, A] failure with a typed reason (domain errors) wrap code that throws (Java APIs, parsing) truly exceptional, unrecoverable situations