Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's choice in implementing Option

Tags:

scala

How it's done in Scala:

  sealed trait Option[+A] {
    def get: A
    def isEmpty: Boolean
    def map[B](f: A => B): Option[B] =
      if (isEmpty) None else Some(f(this.get))
  }
  object None extends Option[Nothing] {
    def isEmpty = true
    def get = throw new NoSuchElementException("None.get")
  }
  case class Some[+A](x: A) extends Option[A] {
    def isEmpty = false
    def get = x
  }

How I would assume it in OOP world:

  sealed trait Option[+A] {
    def map[B](f: A => B): Option[B]
  }
  object None extends Option[Nothing] {
    def map[B](f: Nothing => B): Option[B] = this
  }
  case class Some[+A](get: A) extends Option[A] {
    def map[B](f: A => B): Option[B] = Some(f(get))
  }

What's wrong with the latter?

Functional programming in Scala is using match in Option[A] trait, which is the third way (looks like Haskell, but why?) Why not utilize subtype polymorphism?

UPDATE: Third way I mentioned:

sealed trait Option[+A] {
  def map[B](f: A => B): Option[B] = this match {
    case None => None
    case Some(a) => Some(f(a))
  }
}
object None extends Option[Nothing] {
}
case class Some[+A](get: A) extends Option[A] {
}
like image 408
Victor Moroz Avatar asked Nov 11 '22 01:11

Victor Moroz


1 Answers

I'm not sure whether you intended to, but you left out the declarations of isEmpty and get, which are needed by anyone that wants to check the contents of an arbitrary Option without needing to downcast to Some. Since both of these methods need to be defined by both subclasses, and since map can be defined in terms of them, I think the reasoning was that it would be better to define map in one place leveraging the subclass implementations of the other methods, rather than defining map in three places.

like image 164
reggert Avatar answered Nov 14 '22 21:11

reggert