There have been earlier suggestions for an alternative to `fallthrough` that 
would continue matching cases; I think that is much more likely to get support 
than a whole new construct with only a subtle difference from an existing 
one—would that be an acceptable alternative to you?

> On Nov 17, 2017, at 12:06 PM, Peter Kamb via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> ## Title
> 
> Add `match` statement as `switch`-like syntax alternative to `if case` 
> pattern matching
> 
> ## Summary:
> 
> The syntax of the `switch` statement is familiar, succinct, elegant, and 
> understandable. Swift pattern-matching tutorials use `switch` statements 
> almost exclusively, with small sections at the end for alternatives such as 
> `if case`.
> 
> However, the `switch` statement has several unique behaviors unrelated to 
> pattern matching. Namely:  
> 
>  - Only the *first* matching case is executed. Subsequent matching cases are 
> not executed.
>  - `default:` case is required, even for expressions where a default case 
> does not make sense.
> 
> These behaviors prevent `switch` from being used as a generic 
> match-patterns-against-a-single-expression statement.
> 
> Swift should contain an equally-good pattern-matching statement that does not 
> limit itself single-branch switching.
> 
> ## Pitch:
> 
> Add a `match` statement with the same elegant syntax as the `switch` 
> statement, but without any of the "branch switching" baggage.
> 
> ```
> match someValue {
> case patternOne:
>     always executed if pattern matches
> case patternTwo:
>     always executed if pattern matches
> }
> ```
> 
> The match statement would allow a single value to be filtered through 
> *multiple* cases of pattern-matching evaluation.
> 
> ## Example:
> 
> ```
> struct TextFlags: OptionSet {
>     let rawValue: Int
>     static let italics = TextFlags(rawValue: 1 << 1)
>     static let bold    = TextFlags(rawValue: 1 << 2)
> }
> 
> let textFlags: TextFlags = [.italics, .bold]
> 
> 
> 
> // SWITCH STATEMENT
> switch textFlags {
> case let x where x.contains(.italics):
>     print("italics")
> case let x where x.contains(.bold):
>     print("bold")
> default:
>     print("forced to include a default case")
> }
> // prints "italics"
> // Does NOT print "bold", despite .bold being set.
> 
> 
> 
> // MATCH STATEMENT
> match textFlags {
> case let x where x.contains(.italics):
>     print("italics")
> case let x where x.contains(.bold):
>     print("bold")
> }
> // prints "italics"
> // prints "bold"
> ```
> 
> ## Enum vs. OptionSet
> 
> The basic difference between `switch` and `match` is the same conceptual 
> difference between `Emum` and an `OptionSet` bitmask.
> 
> `switch` is essentially designed for enums: switching to a single logical 
> branch based on the single distinct case represented by the enum.
> 
> `match` would be designed for OptionSet bitmasks and similar constructs. 
> Executing behavior for *any and all* of the following cases and patterns that 
> match.
> 
> The programmer would choose between `switch` or `match` based on the goal of 
> the pattern matching. For example, pattern matching a String. `switch` would 
> be appropriate for evaluating a String that represents the rawValue of an 
> enum. But `match` would be more appropriate for evaluating a single input 
> String against multiple unrelated-to-each-other regexes.
> 
> ## Existing Alternatives
> 
> `switch` cannot be used to match multiple cases. There are several ways "test 
> a value against multiple patterns, executing behavior for each pattern that 
> matches", but none are as elegant and understandable as the switch statement 
> syntax.
> 
> Example using a string of independent `if case` statements:
> 
> ```
> if case let x = textFlags, x.contains(.italics) {
>     print("italics")
> }
> 
> if case let x = textFlags, x.contains(.bold) {
>     print("bold")
> }
> ```
> 
> ## `match` statement benefits:
> 
>  - Allow filtering a single object through *multiple* cases of pattern 
> matching, executing *all* cases that match.
> 
>  - A syntax that exactly aligns with the familiar, succinct, elegant, and 
> understandable `switch` syntax.
> 
> - The keyword "match" highlights that pattern matching will occur. Would be 
> even better than `switch` for initial introductions to pattern-matching.
> 
>  - No need to convert between the strangely slightly different syntax of 
> `switch` vs. `if case`, such as `case let x where x.contains(.italics):` to 
> `if case let x = textFlags, x.contains(.italics) {`
> 
>  - Bring the "Expression Pattern" to non-branch-switching contexts. 
> Currently: "An expression pattern represents the value of an expression. 
> Expression patterns appear only in switch statement case labels."
> 
>  - A single `match controlExpression` at the top rather than 
> `controlExpression` being repeated (and possibly changed) in every single `if 
> case` statement.
> 
>  - Duplicated `controlExpression` is an opportunity for bugs such as typos or 
> changes to the expression being evaluated in a *single* `if case` from the 
> set, rather than all cases.
> 
>  - Reduces to a pretty elegant single-case. This one-liner is an easy "just 
> delete whitespace" conversion from standard multi-line switch/match syntax, 
> whereas `if case` is not.
> 
> ```
>  match value { case pattern:
>     print("matched")
> }
> ```
> 
>  - Eliminate the boilerplate `default: break` case line for non-exhaustible 
> expressions. Pretty much any non-Enum type being evaluated is 
> non-exhaustible. (This is not the *main* goal of this proposal.)
> 
> ## Prototype
> 
> A prototype `match` statement can be created in Swift by wrapping a `switch` 
> statement in a loop and constructing each case to match only on a given 
> iteration of the loop:
> 
> ```
> match: for eachCase in 0...1 {
> switch (eachCase, textFlags) {
> case (0, let x) where x.contains(.italics):
>     print("italics")
> case (1, let x) where x.contains(.bold):
>     print("bold")
> default: break }
> }
> 
> // prints "italics"
> // prints "bold"
> ```
> 
> ## Notes / Discussion:
> 
> - Other Languages - I've been unable to find a switch-syntax non-"switching" 
> pattern-match operator in any other language. If you know of any, please post!
> 
> - Should `match` allow a `default:` case? It would be easy enough to add one 
> that functioned like switch's default case: run if *no other* cases were 
> executed. But, conceptually, should a "match any of these patterns" statement 
> have an else/default clause? I think it should, unless there are any strong 
> opinions.
> 
> - FizzBuzz using proposed Swift `match` statement:
> 
> ```
> for i in 1...100 {
>     var output = ""
>     match 0 {
>     case (i % 3): output += "Fizz"
>     case (i % 3): output += "Buzz"
>     default:      output = String(i)
>     }
>     
>     print(output)
> }
> 
> // `15` prints "FizzBuzz"
> ```
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to