Note that there are some explanatory texts on larger screens.

plurals
  1. POReplacing case class inheritance with extractors preserving exhaustiveness checks in Scala
    text
    copied!<p>I have a simple class hierarchy that represents a graph-like structure with several distinct types of vertexes implemented using case classes:</p> <pre><code>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 </code></pre> <p>This allows me to write match blocks like this:</p> <pre><code>def test (x: Node) = x match { case _ : Arc =&gt; "got arc" case _ : Vertex =&gt; "got vertex" } </code></pre> <p>or like this:</p> <pre><code>def test (x: Node) = x match { case _ : Arc =&gt; "got arc" case c : Vertex =&gt; c match { case _ : VertexType1(a) =&gt; "got type 1 vertex " + a case _ : VertexType2(a) =&gt; "got type 2 vertex " + a } } </code></pre> <p>Note that this implementation has the following properties:</p> <p>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.</p> <p>2) In both vertex-type-specific and non-vertex-type-specific match blocks the exhaustiveness of pattern matching is checked.</p> <p>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). </p> <p>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?</p> <p><strong>EDIT</strong>: I have added a constructor parameter to the VertexType classes so that the match is not performed only on types.</p> <p>My current implementation without the case classes is as follows:</p> <pre><code>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) } </code></pre> <p>And the test code:</p> <pre><code>def test (x: Node) = x match { case _ : Arc =&gt; "got arc" case v : Vertex =&gt; v match { case VertexType1(a) =&gt; "got vertex type 1 " + a } } </code></pre> <p>I expect a warning about non-exhaustive match in the second block (VertexType2 is never matched), but there isn't one.</p> <p><em>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.</em></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload