Reputation: 3694
The swift switch statement (tested in Xcode 6.1) allows repeated switch values. See code below which compiles and runs without error. Apparently, the first matching value is the executed case. Subsequent cases are ignored. Is this a bug or feature? If a feature, how is it useful?
class SwitchTest{
enum E {
case one, two, three
}
func test() {
switchStmt(E.one) // outputs: "one, two"
switchStmt(E.two) // outputs: "one, two"
switchStmt(E.three) //outputs: "three, two"
}
func switchStmt(e : E)
{
switch (e){
case .one, .two:
println("one, two")
case .three, .two:
println("three, two")
case .one:
println("one")
case .two:
println("two")
}
}
}
Upvotes: 1
Views: 2961
Reputation: 882366
It's only a bug if the documentation says it does one thing but it actually does another. Anything where the documentation remains silent on the matter is technically only a disagreement between implementer and user.
However, in this case, the documentation does not remain silent on the matter, it states quite clearly (my emphasis):
It then executes an appropriate block of code, based on the first pattern that matches successfully.
The reason it's like this is probably to do with the fact that, unlike C, you're not limited to simple matches. You can provide, in the case
stanza, single values, lists of single values, ranges, tuples, bindings, additional clauses like where
, and the mandatory default
case if you haven't already trapped all possible values of the type.
In that sense, it's quite logical. It's just a process of comparing the check value against every case
stanza in order and executing the first match, regardless of whether it would match those below as well.
In terms of usefulness, that sequential nature will come in handy if you wanted to specify specific cases at the top and more general ones below, such as with the code:
switch num {
case 2, 3, 5, 7, 11, 13, 17, 19:
println("prime, 1 <= x <= 20");
case 1...20: // don't need 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20
println("non-prime, 1 <= x <= 20");
default:
println("x < 1 or x > 20");
}
With the sequential checking nature and specific-to-general-case flow, you can simplify the later cases.
Upvotes: 5
Reputation: 802
This should most definitely be a syntax error! This will be the source of innumerable copy/paste errors.
Upvotes: 0
Reputation: 62062
This is a feature--not a bug. It's usefulness is made clear by less simple cases.
Consider this example from the official documentation:
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
println("(0, 0) is at the origin")
case (_, 0):
println("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
println("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
println("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
println("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
Consider that if somePoint
had a value of (0,0)
, all of the cases would be true
. And if the tuple were specifically (Int, Int)
, the final case: case (-2...2, -2...2):
could potentially be fully written out (25 combinations) in a comma separated list, more similar to your example. We should want that to disallow our specific case of case (0, 0):
, should we?
If we only define our cases in the way we're used to with a standard C-style switch
statement, it doesn't make much sense... but then, giving multiple values in a single case isn't a C-style switch
statement either.
The example in your question is a bad example of a good feature of the Swift switch
statement.
It should be noted though that if we were to reorder the cases here, we could easily end up with switch
where it's impossible for one of the cases to ever execute. And it might be nice to get a warning generated if we build this sort of switch
statement (for example, what happens if we move case (0, 0):
right before the default).
But, consider that the following generates no warning:
for i in 2...1 {
println(i)
}
It should, however, be noted that this will crash: fatal error: Can't form Range with end < start
.
The point is, Xcode won't catch absolutely everything, so I'm not sure why we'd pick on switch
statements. A simple case like the example in your question might seem easy, but when we consider the totality of the complexity of Swift switch
statements, I'm not sure I want a lot of time spent analyzing my switch
statements like this.
Upvotes: 1