Option

Option

Use Constructor Methods

To create Option type value, instead of doing Some(value) or None, use data constructors provided by FP libraries like Scalaz and Cats.

import cats.implicits._
// No
Some(1)
// res0: Some[Int] = Some(1)
// Yes
1.some
// res1: Option[Int] = Some(1)
// No
None
// res2: None.type = None
// Yes
none[Int]
// res3: Option[Int] = None

Why?

As you can see above, Some(1) does not create an instance of Option[Int] type yet Some[Int].

List(Some(1), Some(2))
// res5: List[Some[Int]] = List(Some(1), Some(2))
List(None, None)
// res6: List[None.type] = List(None, None)
List(Some(1), None, Some(2))
// res7: List[Option[Int]] = List(Some(1), None, Some(2))
// What you want is List[Option[Int]]
import cats.implicits._
List(1.some, 2.some)
// res9: List[Option[Int]] = List(Some(1), Some(2))
List(none[Int], none[Int])
// res10: List[Option[Int]] = List(None, None)
List(1.some, none, 2.some)
// res11: List[Option[Int]] = List(Some(1), None, Some(2))
import cats._ // It is only for Applicative[F]
// No
def foo[F[_] : Applicative](n: Int): F[Option[Int]] = {
val r = Applicative[F].pure(Some(n))
r
}
// error: type mismatch;
// found : r.type (with underlying type F[Some[Int]])
// required: F[Option[Int]]
// Note: Some[Int] <: Option[Int], but type F is invariant in type _.
// You may wish to define _ as +_ instead. (SLS 4.5)
// r
// ^
import cats._
import cats.implicits._
// Yes
def foo[F[_] : Applicative](n: Int): F[Option[Int]] = {
val r = Applicative[F].pure(n.some)
r
}
import cats._
// No
def bar[F[_] : Applicative](n: Int): F[Option[Int]] = {
val r = Applicative[F].pure(None)
r
}
// error: type mismatch;
// found : r.type (with underlying type F[None.type])
// required: F[Option[Int]]
// Note: None.type <: Option[Int], but type F is invariant in type _.
// You may wish to define _ as +_ instead. (SLS 4.5)
// r
// ^
import cats._
import cats.implicits._
// Yes
def bar[F[_] : Applicative](n: Int): F[Option[Int]] = {
val r = Applicative[F].pure(none[Int])
r
}

No Get!

Never use Option.get to get the value in it as it may cause a NoSuchElementException if Option is None.

val n = None.get
// java.util.NoSuchElementException: None.get
// at scala.None$.get(Option.scala:529)
// at repl.MdocSession$App28$$anonfun$20.apply$mcV$sp(option.md:189)
// at repl.MdocSession$App28$$anonfun$20.apply(option.md:188)
// at repl.MdocSession$App28$$anonfun$20.apply(option.md:188)

There are three ways to get and use the value properly.

Pattern Matching

// import cats.implicits._ is only for .some and none.
import cats.implicits._
val maybeNum = 999.some
// maybeNum: Option[Int] = Some(999)
maybeNum match {
case Some(n) =>
println(s"The number is $n")
case None =>
println("Error no number found")
}
// The number is 999
val maybeNum2 = none[Int]
// maybeNum2: Option[Int] = None
maybeNum2 match {
case Some(n) => n + 1
case None => 0
}
// res31: Int = 0

Catamorphism

Use fold. It's not so different from pattern matching.

// import cats.implicits._ is only for .some and none.
// fold is from Scala not Cats.
import cats.implicits._
// Option.fold(NoneCase)(n => do something with n)
val maybeNum = 999.some
// maybeNum: Option[Int] = Some(999)
maybeNum.fold(0)(x => x + 1)
// res36: Int = 1000
val maybeNum2 = none[Int]
// maybeNum2: Option[Int] = None
maybeNum2.fold(0)(x => x + 1)
// res37: Int = 0

fold is exactly the same as doing map then getOrElse.

import cats.implicits._
val maybeNum = 999.some
// maybeNum: Option[Int] = Some(999)
maybeNum.fold(0)(x => x + 1) // is equivalent to
// res39: Int = 1000 // is equivalent to
maybeNum.map(x => x + 1).getOrElse(0)
// res40: Int = 1000
val maybeNum2 = none[Int]
// maybeNum2: Option[Int] = None
maybeNum2.fold(0)(x => x + 1) // is equivalent to
// res41: Int = 0 // is equivalent to
maybeNum2.map(x => x + 1).getOrElse(0)
// res42: Int = 0

getOrElse

Or simply use getOrElse.

// import cats.implicits._ is only for .some and none.
// getOrElse is from Scala not Cats
import cats.implicits._
val maybeNum = 999.some
// maybeNum: Option[Int] = Some(999)
maybeNum.map(x => x + 1).getOrElse(0)
// res44: Int = 1000
val maybeNum2 = none[Int]
// maybeNum2: Option[Int] = None
maybeNum2.map(x => x + 1).getOrElse(0)
// res45: Int = 0