I have a simple class hierarchy that represents a graph-like structure with several distinct types of vertexes implemented using case classes:
sealed trait Node
sealed abstract case class Vertex extends Node
case class Arc extends Node
case class VertexType1 (val a:Int) extends Vertex
case class VertexType2 (val b:Int) extends Vertex
This allows me to write match blocks like this:
def test (x: Node) = x match {
case _ : Arc => "got arc"
case _ : Vertex => "got vertex"
}
or like this:
def test (x: Node) = x match {
case _ : Arc => "got arc"
case c : Vertex => c match {
case _ : VertexType1(a) => "got type 1 vertex " + a
case _ : VertexType2(a) => "got type 2 vertex " + a
}
}
Note that this implementation has the following properties:
1) It allows writing match blocks that differentiate between arcs and vertices, but not between specific vertex types, but also match blocks that do differentiate between vertex types.
2) In both vertex-type-specific and non-vertex-type-specific match blocks the exhaustiveness of pattern matching is checked.
However, inheritance from case classes is deprecated, and the compiler suggests to use extractors instead to support matching on non-leaf nodes (i.e., in the above example, to differentiate between arcs and vertices, but not between vertex types).
The question: is it possible to implement a similar class hierarchy without using case class inheritance, but still having pattern exhaustiveness checks performed by the compiler in both use cases shown above?
EDIT: I have added a constructor parameter to the VertexType classes so that the match is not performed only on types.
My current implementation without the case classes is as follows:
sealed trait Node
sealed abstract class Vertex extends Node
class Arc extends Node
class VertexType1 (val a:Int) extends Vertex
class VertexType2 (val b:Int) extends Vertex
object VertexType1 {
def unapply (x : VertexType1) : Some[Int] = Some(x.a)
}
object VertexType2 {
def unapply (x : VertexType2) : Some[Int] = Some(x.b)
}
And the test code:
def test (x: Node) = x match {
case _ : Arc => "got arc"
case v : Vertex => v match {
case VertexType1(a) => "got vertex type 1 " + a
}
}
I expect a warning about non-exhaustive match in the second block (VertexType2 is never matched), but there isn't one.
Actually, Scala compilers before 2.9.0-RC3 produce a warning that I expect to see, but versions starting with RC3 (including 2.9.0 and 2.9.0-1) do not, which is rather confusing.