I must have some basic misunderstanding of the Scala 'match' semantics or the compiler logic. This code:
val stageStart:Int = 0
val stageShutDown:Int = Int.MaxValue
val stageErrorReport:Int = Int.MinValue
def stageString(stage:Int):String = stage match {
case stageStart => "Start"
case stageShutDown => "End"
case stageErrorReport => "Error"
case _ => "Step " + String.valueOf(stage)
}
results in "Unreachable Code" errors on the last 3 'case' statements? If instead of the names you substitute the actual values (0, Int.MaxValue, Int.MinValue) it compiles -- but now I've hard-coded values that should be referenced by their names (for all the usual reasons). Since a 'val' can never change, shouldn't the first version also work?
There is a subtle yet important feature: If the identifier in case
rules start with a lower-case letter, they're always treated as variables. So the first case
matches always (storing stage
into variable stageStart
) and the rest 3 are unreachable. You need to define the constants with upper case letters as
val StageStart:Int = 0
val StageShutDown:Int = Int.MaxValue
val StageErrorReport:Int = Int.MinValue
def stageString(stage:Int):String = stage match {
case StageStart => "Start"
case StageShutDown => "End"
case StageErrorReport => "Error"
case _ => "Step " + String.valueOf(stage)
}
Then they won't be treated as variables but as constants to pattern-match on.
See also this answer for Naming convention for Scala constants?
The issue is that when you use a variable that starts with a lowercase character, the pattern matcher thinks that you are trying to assign to that variable. So you get this behavior:
val stageStart = 0
val stage = 5
def stageString(stage: Int) = stage match {
case stageStart => println(startStage) // prints "5"
}
Of course, a pattern that is simply an assignable variable will match anything, so any subsequent case
will be unreachable.
To solve this, you need to use a "stable identifier". This can be done by putting the lowercased variable in backticks:
val stageStart = 0
def stageString(stage: Int) = stage match {
case `stageStart` => "Start"
}
or renaming the variable so that it starts with an uppercase character:
val StageStart = 0
def stageString(stage: Int) = stage match {
case StageStart => "Start"
}
Also: String.valueOf(stage)
should be rewritten as stage.toString
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With