Scala for Beginners: How to really use Option (and Try and Either)

Stick figure saying “I think I get the gist of this. It can’t be too hard to use…”
case class Person(name: String, 
age: Option[Int],
email: Option[String])
def sendEmail(address: String): Boolean
// returns true is successful
def invite(guest: Person): Boolean = {
if (guest.email.isEmpty)
false
else
sendEmail(guest.email.get)
}
println("Guest's email is " + guest.getOrElse("unknown"))

Confession

First lesson: pattern matching

def invite(guest: Contact): Boolean = guest.email match {
case Some(e) => sendEmail(e) // returns true if successful
case None => false
}
scala> def invite(guest: Option[String]): Boolean = guest match {
| case Some(e) => println(e)
| }
^
warning: match may not be exhaustive.
It would fail on the following input: None

Second lesson: map

scala> List("one","two","three").map(s => s.size)
val res1: List[Int] = List(3, 3, 5)
scala> def stringSize(o: Option[String]) = o.map(s => s.size)
def stringSize(o: Option[String]): Option[Int]
scala> stringSize(Some("Hello"))
val res2: Option[Int] = Some(5)
scala> stringSize(None)
val res3: Option[Int] = None
scala> List("one","two","three").map(_.size)
val res1: List[Int] = List(3, 3, 5)
scala> def stringSize(s: Option[String]) = s.map(_.size)

Let’s look at the sibling typeclass Try

scala> def convert(n: String): Try[Int] = Try(n.toInt)
def convert(n: String): scala.util.Try[Int]
scala> convert("3")
val res6: scala.util.Try[Int] = Success(3)
scala> convert("foo")
val res7: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "foo")
scala> convert("5").toOption
val res10: Option[Int] = Some(5)
scala> convert("bar").toOption
val res11: Option[Int] = None
val email: Try[String] = getEmail("bob")
val success: Boolean = if (email.isSuccess) {
sendEmail(email.get)
} else {
false
}
val email: Try[String] = getEmail("bob")
val success = email match {
case Success(addr) => sendEmail(addr) // returns true if success
case Failure(e) => false
}
val email: Try[String] = getEmail("bob")
val success = email.map(addr => sendEmail(addr)).toOption
val success = email.map(sendEmail).toOption
  1. Some(true) if the sendEmail function returned true indicating successful delivery.
  2. Some(false) if sendEmail ran into some problem
  3. None if the earlier getEmail function failed.

While we’re at it, let’s look at Either

def getEmail(custID: String): Either[Int,String]
val email: Left[String] = getEmail("bob")
val status: Either[String, String] = email match {
case Failure(e) => Left("Couldn't get email address")
case Success(e) => {
if (sendEmail(e))
Right(e)
else
Left("Couldn't deliver invite")
}
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store