Saturday 19 September 2015

Null, Option and Either in Scala

1. Null

Null is a subtype of all AnyRef, but not subtype of AnyVal.
You can assign null to instances of any reference type, rather than an Int.

2.  Option

Option is a binary container. Options are either empty(None) or not (Some).
Assume each task returns an Option, where None is returned for empty results and Some wraps a nonempty result.
val results: Seq[Option[Int]] = Vector(Some(10), None, Some(20))

def positive(i: Int): Option(Int) = 
   if (i>0) Some(i) else None

val result2 = for {
  Some(i) - results
} yield (2*i)

The use of Option has the disadvantage that None carries no information that could tell us why no value is available.

For example,
def countLines(fileName: String)={
   var source:Option[Source]=None
   try {
     source = Some(Source.fromFile(fileName))
     val size = source.get.getLine.size 
 } catch {
     case NonFatal(ex) => println("xx")
   } finally{
     for(s<=source)
       s.close
   }
 }

Declare the source to be an Option. Wrap the return Source instance in a Some.
Use a for comprehension when you need to test whether an Option is a Some, in which case you do some work, or is a None, in which case you ignore it.

The crucial feature of Option methods is that the function arguments are only applied if the Option isn't empty. We would like an elegant way to ignore the task results that are empty and just deal with the nonempty results.

val results: Seq[Option[Int]] = Vector(Some(10), None, Some(20))

val results2 = for{
    Some(i) <= results;
} yield (2*i)

Some(i)<= results pattern matches on the elements of results, removing the None values and extracting the integers inside the Some values.

Option has a getOrElse() method. A parameter to the getOrElse method is a by-name parameter, which means it is only evaluated if the option on which you invoke is indeed None.

For example,

def withFallback[T](conf: Try[T]): Option[T]= conf match {
    case null  => None
    case value => value.toOption
  }

val inputPath = withFallback[String](Try(config.getString("input")),"")
          .getOrElse("path")


Some is a case class, it is perfectly possible to use it in a pattern.


val user = User(2, "Doe", None)

val gender = user.gender match {
    case Some(gender) = gender
    case None = "not specified"
}


Options can be viewed as collections. Perform some side-effect only if a specific optional value is present.

optionObject.foreach(user => println(user.firstName))

The function passed to foreach will be called exactly once, if the Option is Some, or never, if it is None.

3. Either 

Either is the container that holds one and only one of two things. In other words, where Option handled the case of zero or one items, Either handles the case of one item or another. Either is a parameterized type with two parameters, Either[+A, +B]. Recall that +A indicates that Either is covariant in the type parameter A. This means if you need a value of type Either[Any, Any], you can use an instance of type Either[String, Int]. Either is also a sealed abstract class with two subclasses defined, Left[A] and Right[B]. The Left value is used to hold the error indicator, and the normal return value is Right.

def positive(i: Int): Either[String, Int] =
    if (i>0) Right(i) else Left(s"nonpositive number $i")

No comments:

Post a Comment