Reputation: 676
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.
Upvotes: 5
Views: 878
Reputation: 297195
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.
Upvotes: 10