1

NOTE: this question is not asking for help solving FizzBuzz. Please don't post answers that just solve FizzBuzz. Answers to this question should relate to matching multiple true switch cases

Consider an attempted FizzBuzz solution in Swift using a switch statement:

func fizzBuzz(forInt int: Int) -> String {
    var output = ""
    switch 0 {
    case (int % 3): output += "Fizz"
    case (int % 5): output += "Buzz"
    default:
        output = String(int)
    }

    return output
}

// FAILS
assert(fizzBuzz(forInt: 15) == "FizzBuzz", "15 should output `FizzBuzz`, not `Fizz`!")

The correct output on iteration 15 should be "FizzBuzz" because 15 is divisible by both 3 and 5.

But the program above outputs "Fizz" because only the first passing case is executed.

The Swift docs state:

A switch statement executes an appropriate block of code based on the first pattern that matches successfully.

It seems that it would be useful for there to be a similar, switch-like statement that matches any true case rather than just the first.

Pattern matching patterns can currently be used in the following situations:

You use these patterns in a case label of a switch statement, a catch clause of a do statement, or in the case condition of an if, while, guard, or for-in statement.

Matching multiple patterns seems impossible in Swift. Options considered:

fallthrough

Switch fallthrough allows one executed case to fall into and execute the physically next case, but without actually testing the case statement. It does not allow multiple, arbitrary, unordered cases to be executed only if matching.

multiple if statements

Multiple if statements produce the desired behavior, but are annoying for the same reasons switch is often preferred over if-else blocks.

if (i % 3 == 0) {
    // ...
}
if (i % 5 == 0) {
    // ...
}

Namely re-stating the variable being tested in each case, no compiler protection that we're evaluating the same single variable against multiple cases, etc.

tuples, etc.

Yes, it's possible to do things like switch on a tuple to produce the correct output value. But that involves duplicating code inside the cases.

switch (i % 3, i % 5) {
case (0, 0):
    output += "FizzBuzz"
case (0, _):
    output += "Fizz"
case (_, 0):
    output += "Buzz"

The goal of this question is to have only 2 cases for "Fizz" and "Buzz". Combined execution of the true cases should produce "FizzBuzz", not a separate 3rd case that duplicates the strings.

Related:

Switch to match multiple cases from OptionSetType

Question:

Does there exist a switch-like pattern matching control flow statement that matches any and all true cases? If not in Swift, do any languages contain such a feature?

pkamb
  • 33,281
  • 23
  • 160
  • 191
  • 1
    Is this actually a conceptual question or do you want to solve this exact issue? This can be solved easily using a switch statement. – Dávid Pásztor Nov 10 '17 at 22:02
  • @DávidPásztor how so? I'm interested in execution of all matching cases in a switch statement. Yes, it's easy enough to get the correct output of "FizzBuzz" through other means :P – pkamb Nov 10 '17 at 22:12
  • 1
    https://stackoverflow.com/questions/33975542/swift-2-expression-pattern-of-type-bool-cannot-match-values-of-type-int/33975661#33975661 – Leo Dabus Nov 10 '17 at 22:54
  • 1
    https://stackoverflow.com/questions/25279000/switch-statement-in-swift – Leo Dabus Nov 10 '17 at 22:55
  • @LeoDabus both those links seem to be to successful implementations of FizzBuzz in Swift, but *not* anything to do with matching **multiple** `switch` cases. – pkamb Nov 10 '17 at 23:45
  • 2
    If they were exactly duplicate of your question I would just close it. Considering that you have not posted any reference to them in your question I thought you might want to take a look at them. – Leo Dabus Nov 10 '17 at 23:50
  • Have you ever though about adding a case statement to that switch: `case (int % 15): output = "FizzBuzz"`? – Code Different Nov 19 '17 at 01:34
  • https://stackoverflow.com/questions/46017533/is-there-a-way-to-test-an-optionset-with-a-switch-statement – pkamb Oct 30 '18 at 03:22

2 Answers2

0

This loop-nested switch syntax executes each true case in order, not just the first true case.

for i in 1...100 {
    var output = ""

    for eachCase in 0...1 {
        switch (eachCase, 0) {
        case (0, i % 3): output += "Fizz"
        case (1, i % 5): output += "Buzz"
        default: break }
    }

    if output.isEmpty {
        output = String(i)
    }

    print(output)
}

I'll leave it to the reader to determine situations where this is better behavior than alternative such as multiple if statements.

pkamb
  • 33,281
  • 23
  • 160
  • 191
0

There was a Swift evolution proposal to introduce a continue statement within Switch cases, which would resume pattern matching against the remaining cases.

[swift-evolution] [Pitch] Introduce continue to switch statements

This proposal completes the switch statement's control flow transfer suite by introducing continue. This change adds functionality that many developers expect (but do not get) from fallthrough.

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023955.html

https://gist.github.com/erica/04835de3d3d9121ef7308dd9b093158a

Introducing continue means "resume pattern matching after executing this case clause". It offers more nuanced control than currently exists within switch.

Community
  • 1
  • 1
pkamb
  • 33,281
  • 23
  • 160
  • 191