tags:

views:

140

answers:

2

I want to leverage the warning that Scala issues when a matching is missing ("not exhaustive") - so that I don't forget one (I have dozens). The following simplified example shows my attempt:

sealed case class MESSAGE()
class SUCCESS_MESSAGE extends MESSAGE
class FAILURE_MESSAGE extends MESSAGE

def log(str: String, msgType: MESSAGE) {
    msgType match {
        case t:SUCCESS_MESSAGE => println("FAILURE: " + str)
        case t:FAILURE_MESSAGE => println("SUCCESS: " + str)
    }
}

The problem is that it says "match is not exhaustive!" although all possible combinations are listed. If I'd put the "case _ =>" in there, the whole point of the warning is invalidated for me because I could add

class INFO_MESSAGE extends MESSAGE

and no warning would be issued.

Any thoughts?

+16  A: 

You missed one case: The message might be an instance of MESSAGE, not one of its subclasses.

If you want to make this case impossible, you need to make MESSAGE abstract. This will make the warning go away.

sepp2k
thanks - this fixed it :)yet Kevin's solution seemed 'purer'
stephanos
+19  A: 

Ideally, you shouldn't be extending a concrete class, and especially not a case class!

Given that there's no potential to customise SUCCESS_MESSAGE and FAILURE_MESSAGE, you probably also want to make these singletons.

Finally, underscores are a Bad Thing(tm) in Scala variable or class names. All UPPERCASE names are not idiomatic either. So:

sealed trait Message
case object SuccessMessage extends Message
case object FailureMessage extends Message

def log(str: String, msgType: Message) = msgType match {
  case SuccessMessage => println("Success: " + str)
  case FailureMessage => println("Failure: " + str)
}

Alternatively, and I would recommend this, you can wrap the actual message string:

sealed trait Message { def msg: String }
case class Success(msg:String) extends Message
case class Failure(msg:String) extends Message

def log(msg: Message) = msg match {
  case Success(str) => println("Success: " + str)
  case Failure(str) => println("Failure: " + str)
}
Kevin Wright
+1 for complete code review. :-)
missingfaktor
s/in Scala variable names/in Scala class names/
Alexey Romanov
variable OR class names, if you want to be exact :)
Kevin Wright
thanks for all the info and advice!
stephanos
The first example still suffers the same problem, since `Message` is not marked `abstract`. The second example is ok because the abstract method `msg` guarantees that `Message` is abstract as well.
Daniel
How bizarre! I can't imagine any possible way of instantiating the trait...
Kevin Wright