4

Let's say I have

sealed trait AlphaNumericChar

sealed trait AlphaChar
case object A extends AlphaNumericChar with AlphaChar
case object B extends AlphaNumericChar with AlphaChar

sealed trait NumericChar
case object One extends AlphaNumericChar with NumericChar
case object Two extends AlphaNumericChar with NumericChar

This structure allows me to pattern match on AlphaNumericChar and get all A,B,One,Two and similarly pattern match on AlphaChar and NumericChar and get only the relevant objects.

What it doesn't allow me, is to write:

def foo(x: AlphaNumericChar) = ???
def bar(x: AlphaChar) = foo(x)

ie, proxy calls to foo for only certain types. I can of course write instead:

def baz(x: AlphaNumericChar with AlphaChar) = foo(x) 

and that would work but that's perhaps a bit ugly.

Alternative is to make AlphaChar and NumericChar extend AlphaNumericChar but that would mess with my pattern matches on AlphaNumericChar as I will now have to handle _:AlphaChar and _:NumericChar in addition to my case objects which is undesirable.

Is there a way of somehow having the best of two worlds? ie.

  • The exhaustive list of pattern match entries on AlphaChar/NumericChar has only two elements.
  • The exhaustive list of pattern match entries on AlphaNumericChar has only two elements.
  • I can have the bar function above working without resorting to the baz syntax.
Maths noob
  • 1,684
  • 20
  • 42

1 Answers1

0

Extending AlphaNumericChar shouldn't be a problem. Something like this works fine:

sealed trait AlphaNumericChar

sealed trait AlphaChar extends AlphaNumericChar

case object A extends AlphaChar
case object B extends AlphaChar

sealed trait NumericChar extends AlphaNumericChar

case object One extends NumericChar
case object Two extends NumericChar

def foo(x: AlphaNumericChar) = x match {
  case One => println("hi")
  case Two => println("bye")
  case A => println("foo")
  case B => println("bar")
}

def bar(x: AlphaChar) = foo(x)

def aThirdFunction(y: NumericChar) = y match {
  case One => println("eggs")
  case Two => println("beans")
}

foo(One)  // hi
foo(Two)  // bye
foo(A)    // foo
foo(B)    // bar
bar(A)    // foo
bar(B)    // bar
aThirdFunction(One) // eggs
aThirdFunction(Two) // beans

Unless I've misunderstood what you want?

James Whiteley
  • 3,363
  • 1
  • 19
  • 46
  • yes I think I wasn't clear enough. I am talking about the compiler generated exhaustive list of cases. Your solution which I believe is my second option, works but the compiler should warn you about case exhaustivity in `foo`. – Maths noob Nov 22 '19 at 17:31
  • 1
    https://scastie.scala-lang.org/iaFRC4BARkuIJSeF7I6fgw this doesn't complain, but if you delete one of the case statements (and its corresponding test) Scastie complains that your matches aren't exhaustive. – James Whiteley Nov 22 '19 at 17:32
  • interesting. I wrote my example with `2.12.10`. But I just tested your example with `2.12.10` and it's fine with that too. Guess it's not a problem with the compiler then and one with the IntelliJ plugin that tries to auto-generate my cases. – Maths noob Nov 22 '19 at 17:37
  • Yeah IntelliJ isn't perfect. Let me know if you have any other queries/concerns. – James Whiteley Nov 22 '19 at 18:01