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] {
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With