Option in Scala

    Scala has a type to hold optional values named Option. It can be of two types:
    Some(x) , where x is an actual value or None , which represents a missing value.

    An Option is actually an abstract class with two implementations where Some is a case class, and None is an object.

    Optional values are generated as a result of some operations on the Scala collections.

    For example:

    val mapExample = Map("One" -> 1, "Two" -> 2)
    
    val result: Option[Int] = mapExample.get("One")
    
    val result: Option[Int] = mapExample.get("Three")
    Output:
    val mapExample: scala.collection.immutable.Map[String,Int] = Map(One -> 1, Two -> 2)
    
    val result: Option[Int] = Some(1)
    
    val result: Option[Int] = None

    How to Extract Value From an Option?

    1) Using get method

    Example:

    Val res0 = Some("Name").get
    
    None.get

    Output:

    val res0: String = Name
    
    
    java.util.NoSuchElementException: None.get
    
      at scala.None$.get(Option.scala:627)
    
      ... 36 elided

    The get method on the None type can result in an error. So, we should first check if Option has a value before using get on Option. To check if the Option field has some value defined, you can use the method “ isDefined ”.

    2) Using getOrElse

    getOrElse method provides one flexibility on top of the get method to return a default value if the Option does not contain any value(i.e., it is of None type) but getOrElse is not type-safe.

    val res4 = Some("Name").getOrElse("")
    
    
    val res5 = None.getOrElse("default value")

    Output:

    val res4: String = Name
    
    val res5: String = default value

    We can look at the below example to see how this method is not type-safe.

    Some("Name").getOrElse(5)             //Output will result into Any type

    When getOrElse is applied on an Option[String], ideally, it should result in string type after extracting value from it. But getOrElse let us provide a different type value in the default argument.

    3) Using fold

    Below is the declaration of the fold method:

    final def fold[B](ifEmpty : => B)(f : scala.Function1[A, B])

    The fold method takes two arguments, the first will be executed if the option type is None, and the second will be executed if the option type is Some.

    Below are examples of how you can use fold.

    println(Some("Name").fold("default")(identity))
    
    println(Some("Name").fold("defaultValue")(_.toString))
    
    println(Some("Name").fold("")(_.toUpperCase()))
    
    println(None.fold("defaultValue")(_.toString))

    Output:

    Name
    Name
    NAME
    defaultValue

    One additional benefit of using fold is that fold is typesafe, so if you try to provide different type values in both arguments, it will lead to an error.

    Example:

    Some("Name").fold(5)(_.toUpperCase)
    
    // above statement will lead to compilation part. The first argument suggests that the return type is Int, while the second argument suggests that the return type is String.

    4) Using pattern match

    Example:

    val response = Option("TGB Learner")
    
    val x =  response match {
     case Some(data) => "TGB Learner"
     case None =>  "Technology excites me"
    }
    
    println(x)

    Output:

    val response: Option[String] = Some(TGB Learner)
    
    val x: String = TGB Learner