Garrett Bluma
Garrett Bluma

Reputation: 1312

How to account for all cases of an enum on the right-hand side of a pattern match

Exhaustive pattern matching is great, but it only appears to work on the left-hand side of the case (=>) operator.

I am curious if there is a way that a person can verify that the output of a function (or expression) can be bound to that enumeration. The goal would be to have the compiler tell me when I forget to output an item from the enumeration.

In my example, I make use of the following enumeration containing three items:

object MyEnum { 
    sealed trait t 
    case object E1 extends t
    case object E2 extends t
    case object E3 extends t
}

And here is a pattern-match expression that would produce a compile-time warning (as we already know):

def foo( e : MyEnum.t ) : Boolean =
    e match {
        case MyEnum.E1 => true
        case MyEnum.E2 => false
        case MyEnum.E3 => true   // if we leave this line out, we get a warning
    }

Scala would complain if we left MyEnum.E3 out of the pattern matching expression, citing a non-exhaustive pattern match. This is profoundly beneficial, but I wonder if the reverse is possible.

Can we account for all cases of MyEnum.t on the right-hand side of =>?

Here is an example that highlights this:

def bar( s : String ) : Option[MyEnum.t] = 
    s match {
        case "a" => Some(MyEnum.E1)
        case "b" => Some(MyEnum.E2)
        case "c" => Some(MyEnum.E3)  // if we leave this out, no warning
        case _ => None
    }

In this example, if we leave out the line with MyEnum.E3, then the compiler just carries on as if nothing is wrong. The assertion I would like to make, is:

forall MyEnum.t (aliased as e) there exists Some(e) | None

I understand that this could be easily covered by a run-time test, but I'm curious if there is a way to check this statically.

Thanks.

Upvotes: 3

Views: 221

Answers (2)

Robin Green
Robin Green

Reputation: 33063

No, it is not possible, because this is equivalent to the Halting Problem, which was proven unsolvable in 1936.

Upvotes: 0

user1338062
user1338062

Reputation: 12745

I am going to push my luck and claim it is not possible (let's keep this a secret from Odersky). If the Scala compiler was able to detect such situations, I think it would be even slower than it already is ;)

The only way I could see is to define foo similarly to how you have done, and define bar by making it iterate over foo to make a reverse map, but that doesn't make much sense to me, and might not work in your specific case.

I think your case is a very good example for when unit tests are useful, so why not just write one?

Upvotes: 0

Related Questions