<div dir="ltr"><div>## Title</div><div><br></div><div><div>Add `match` statement as `switch`-like syntax alternative to `if case` pattern matching</div></div><div><br></div><div>## Summary:</div><div><br></div><div>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`.</div><div><br></div><div>However, the `switch` statement has several unique behaviors unrelated to pattern matching. Namely:  </div><div><br></div><div> - Only the *first* matching case is executed. Subsequent matching cases are not executed.</div><div> - `default:` case is required, even for expressions where a default case does not make sense.</div><div><br></div><div>These behaviors prevent `switch` from being used as a generic match-patterns-against-a-single-expression statement.</div><div><br></div><div>Swift should contain an equally-good pattern-matching statement that does not limit itself single-branch switching.</div><div><br></div><div>## Pitch:</div><div><br></div><div>Add a `match` statement with the same elegant syntax as the `switch` statement, but without any of the &quot;branch switching&quot; baggage.</div><div><br></div><div>```</div><div>match someValue {</div><div>case patternOne:</div><div>    always executed if pattern matches</div><div>case patternTwo:</div><div>    always executed if pattern matches</div><div>}</div><div>```</div><div><br></div><div>The match statement would allow a single value to be filtered through *multiple* cases of pattern-matching evaluation.</div><div><br></div><div>## Example:</div><div><br></div><div>```</div><div>struct TextFlags: OptionSet {</div><div>    let rawValue: Int</div><div>    static let italics = TextFlags(rawValue: 1 &lt;&lt; 1)</div><div>    static let bold    = TextFlags(rawValue: 1 &lt;&lt; 2)</div><div>}</div><div><br></div><div>let textFlags: TextFlags = [.italics, .bold]</div><div><br></div><div><br></div><div><br></div><div>// SWITCH STATEMENT</div><div>switch textFlags {</div><div>case let x where x.contains(.italics):</div><div>    print(&quot;italics&quot;)</div><div>case let x where x.contains(.bold):</div><div>    print(&quot;bold&quot;)</div><div>default:</div><div>    print(&quot;forced to include a default case&quot;)</div><div>}</div><div>// prints &quot;italics&quot;</div><div>// Does NOT print &quot;bold&quot;, despite .bold being set.</div><div><br></div><div><br></div><div><br></div><div>// MATCH STATEMENT</div><div>match textFlags {</div><div>case let x where x.contains(.italics):</div><div>    print(&quot;italics&quot;)</div><div>case let x where x.contains(.bold):</div><div>    print(&quot;bold&quot;)</div><div>}</div><div>// prints &quot;italics&quot;</div><div>// prints &quot;bold&quot;</div><div>```</div><div><br></div><div>## Enum vs. OptionSet</div><div><br></div><div>The basic difference between `switch` and `match` is the same conceptual difference between `Emum` and an `OptionSet` bitmask.</div><div><br></div><div>`switch` is essentially designed for enums: switching to a single logical branch based on the single distinct case represented by the enum.</div><div><br></div><div>`match` would be designed for OptionSet bitmasks and similar constructs. Executing behavior for *any and all* of the following cases and patterns that match.</div><div><br></div><div>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.</div><div><br></div><div>## Existing Alternatives</div><div><br></div><div>`switch` cannot be used to match multiple cases. There are several ways &quot;test a value against multiple patterns, executing behavior for each pattern that matches&quot;, but none are as elegant and understandable as the switch statement syntax.</div><div><br></div><div>Example using a string of independent `if case` statements:</div><div><br></div><div>```</div><div>if case let x = textFlags, x.contains(.italics) {</div><div>    print(&quot;italics&quot;)</div><div>}</div><div><br></div><div>if case let x = textFlags, x.contains(.bold) {</div><div>    print(&quot;bold&quot;)</div><div>}</div><div>```</div><div><br></div><div>## `match` statement benefits:</div><div><br></div><div> - Allow filtering a single object through *multiple* cases of pattern matching, executing *all* cases that match.</div><div><br></div><div> - A syntax that exactly aligns with the familiar, succinct, elegant, and understandable `switch` syntax.</div><div><br></div><div>- The keyword &quot;match&quot; highlights that pattern matching will occur. Would be even better than `switch` for initial introductions to pattern-matching.</div><div><br></div><div> - 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) {`</div><div><br></div><div> - Bring the &quot;Expression Pattern&quot; to non-branch-switching contexts. Currently: &quot;An expression pattern represents the value of an expression. Expression patterns appear only in switch statement case labels.&quot;</div><div><br></div><div> - A single `match controlExpression` at the top rather than `controlExpression` being repeated (and possibly changed) in every single `if case` statement.</div><div><br></div><div> - 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.</div><div><br></div><div> - Reduces to a pretty elegant single-case. This one-liner is an easy &quot;just delete whitespace&quot; conversion from standard multi-line switch/match syntax, whereas `if case` is not.</div><div><br></div><div>```</div><div> match value { case pattern:</div><div>    print(&quot;matched&quot;)</div><div>}</div><div>```</div><div><br></div><div> - 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.)</div><div><br></div><div>## Prototype</div><div><br></div><div>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:</div><div><br></div><div>```</div><div>match: for eachCase in 0...1 {</div><div>switch (eachCase, textFlags) {</div><div>case (0, let x) where x.contains(.italics):</div><div>    print(&quot;italics&quot;)</div><div>case (1, let x) where x.contains(.bold):</div><div>    print(&quot;bold&quot;)</div><div>default: break }</div><div>}</div><div><br></div><div>// prints &quot;italics&quot;</div><div>// prints &quot;bold&quot;</div><div>```</div><div><br></div><div>## Notes / Discussion:</div><div><br></div><div>- Other Languages - I&#39;ve been unable to find a switch-syntax non-&quot;switching&quot; pattern-match operator in any other language. If you know of any, please post!</div><div><br></div><div>- Should `match` allow a `default:` case? It would be easy enough to add one that functioned like switch&#39;s default case: run if *no other* cases were executed. But, conceptually, should a &quot;match any of these patterns&quot; statement have an else/default clause? I think it should, unless there are any strong opinions.</div><div><br></div><div>- FizzBuzz using proposed Swift `match` statement:</div><div><br></div><div>```</div><div>for i in 1...100 {</div><div>    var output = &quot;&quot;</div><div>    match 0 {</div><div>    case (i % 3): output += &quot;Fizz&quot;</div><div>    case (i % 3): output += &quot;Buzz&quot;</div><div>    default:      output = String(i)</div><div>    }</div><div>    </div><div>    print(output)</div><div>}</div><div><br></div><div>// `15` prints &quot;FizzBuzz&quot;</div><div>```</div></div>