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.
Algebraic Data Types (ADTs for short) are a way of structuring data. They're widely used in Scala due, mostly, to how well they work with pattern matching and how easy it is to use them to make illegal states impossible to represent. There are two basic categories of ADTs: product types. sum types.
Sum Type. The sum type in Scala is implemented by way of inheritance. The values of the sum type can are subtypes associated with logical disjunctions (ORs), where the possible values are this subtype OR that subtype … Here we create a sum type from Option that can either be None , or a Some containing a tuple.
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.
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