Reputation: 15502
I'm looking for the same behavior as the following OCaml code, where the compiler understands the match is exhaustive because we've expressed that the two scrutinees must have the same type:
type circle
type rectangle
type _ figure =
| Circle : int -> circle figure
| Rectangle : int * int -> rectangle figure
let equal_figure : type a. a figure -> a figure -> bool = fun f1 f2 -> match (f1, f2) with
| Circle r1, Circle r2 -> Int.(r1 = r2)
| Rectangle (x1, y1), Rectangle (x2, y2) -> Int.(x1 = x2 && y1 = y2)
(* the compiler knows this match is exhaustive *)
I can port the example directly to Scala and the exhaustiveness-checker does the right thing:
sealed trait CircleMarker
sealed trait RectangleMarker
enum Fig[T]:
case Circle(r: Int) extends Fig[CircleMarker]
case Rectangle(x: Int, y: Int) extends Fig[RectangleMarker]
def equalFig[T](f1: Fig[T], f2: Fig[T]): Boolean = (f1, f2) match
case (Fig.Circle(r1), Fig.Circle(r2)) => r1 == r2
case (Fig.Rectangle(x1, y1), Fig.Rectangle(x2, y2)) => x1 == x2 && y1 == y2
(* the compiler knows this match is exhaustive *)
Is there a more succinct way to express this in Scala, without the phantom CircleMarker
and RectangleMarker
traits?
Upvotes: 0
Views: 108
Reputation: 51658
You can try F-bounds
enum Fig[T <: Fig[T]]:
case Circle(r: Int) extends Fig[Circle]
case Rectangle(x: Int, y: Int) extends Fig[Rectangle]
// sealed trait Fig[T <: Fig[T]]
// object Fig:
// case class Circle(r: Int) extends Fig[Circle]
// case class Rectangle(x: Int, y: Int) extends Fig[Rectangle]
def equalFig[T <: Fig[T]](f1: Fig[T], f2: Fig[T]): Boolean = (f1, f2) match
case (Fig.Circle(r1), Fig.Circle(r2)) => r1 == r2
case (Fig.Rectangle(x1, y1), Fig.Rectangle(x2, y2)) => x1 == x2 && y1 == y2
// def equalFig[T <: Fig[T]](f1: Fig[T], f2: Fig[T]): Boolean = f1 == f2
equalFig(Fig.Circle(1), Fig.Circle(1)) // true
equalFig(Fig.Circle(1), Fig.Circle(2)) // false
equalFig(Fig.Rectangle(1, 2), Fig.Rectangle(1, 2)) // true
equalFig(Fig.Rectangle(1, 2), Fig.Rectangle(1, 3)) // false
// equalFig(Fig.Circle(1), Fig.Rectangle(1, 2)) // doesn't compile
Upvotes: 1