Question

Is there an equivalent to the OO notion of subtyping for the ADT pattern as used in Scala? In particular I would like to add methods to more specialized types. For example, given a generic List ADT:

sealed trait List[+A]
case class Cons[+A](h: A, t: List[A]) extends List[A]
case object Nil[Nothing]

I'd like to define new methods for lists of particular types:

sealed trait List[+A]
sealed trait DuckList extends List[Duck] {
    def feed(l: DuckList) = ...
}

but then I'd also have to define special data constructors (DuckCons, DuckNil) for these new types, and since case classes don't support (case-to-case) inheritance, there is no way to relate a DuckCons to the generic Cons such that it would work in pattern matching, so the generic methods defined for List wouldn't work for DuckList.

Was it helpful?

Solution

Use the type class pattern.

For one example, consider how Ordering is implemented. It adds a method -- compare -- to a set of closed classes, but it does so not by adding the method directly but, instead, providing an instance that has such a method for that particular class. Ordering[Int], to continue with the example, is implemented like this:

trait IntOrdering extends Ordering[Int] {
  def compare(x: Int, y: Int) =
    if (x < y) -1
    else if (x == y) 0
    else 1
}
implicit object Int extends IntOrdering

That is, the object Ordering.Int (for this is inside the object Ordering) implements a method compare that takes two Int as a parameter. This object is provided implicitly, so that the user does not need to pass it explicitly. List's sorted method takes advantage of this:

def sorted[B >: A](implicit ord: math.Ordering[B]): List[A]

Then it can call ord.compare on instances of the list to order them. I encourage you to look at Ordering to understand what it is doing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top