<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Aha! I found a proposal Erica put forth about this a year and a while ago—</div><div class=""><br class=""></div><a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023955.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023955.html</a><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 18, 2017, at 11:30 AM, Peter Kamb <<a href="mailto:peterkamb@gmail.com" class="">peterkamb@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="auto" class=""> > alternative to `fallthrough` that would continue matching cases</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">Yes, that would be interesting to look into. Do you have any references or remember what the proposed keyword was called? Do any other languages have this feature?</div><div dir="auto" class=""><br class=""></div><div dir="auto" class=""><br class=""></div><div class=""><br class=""><div class="gmail_quote"><div class="">On Sat, Nov 18, 2017 at 10:53 AM Kevin Nattinger <<a href="mailto:swift@nattinger.net" class="">swift@nattinger.net</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">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?<br class="">
<br class="">
> On Nov 17, 2017, at 12:06 PM, Peter Kamb via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">
><br class="">
> ## Title<br class="">
><br class="">
> Add `match` statement as `switch`-like syntax alternative to `if case` pattern matching<br class="">
><br class="">
> ## Summary:<br class="">
><br class="">
> 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`.<br class="">
><br class="">
> However, the `switch` statement has several unique behaviors unrelated to pattern matching. Namely:<br class="">
><br class="">
> - Only the *first* matching case is executed. Subsequent matching cases are not executed.<br class="">
> - `default:` case is required, even for expressions where a default case does not make sense.<br class="">
><br class="">
> These behaviors prevent `switch` from being used as a generic match-patterns-against-a-single-expression statement.<br class="">
><br class="">
> Swift should contain an equally-good pattern-matching statement that does not limit itself single-branch switching.<br class="">
><br class="">
> ## Pitch:<br class="">
><br class="">
> Add a `match` statement with the same elegant syntax as the `switch` statement, but without any of the "branch switching" baggage.<br class="">
><br class="">
> ```<br class="">
> match someValue {<br class="">
> case patternOne:<br class="">
> always executed if pattern matches<br class="">
> case patternTwo:<br class="">
> always executed if pattern matches<br class="">
> }<br class="">
> ```<br class="">
><br class="">
> The match statement would allow a single value to be filtered through *multiple* cases of pattern-matching evaluation.<br class="">
><br class="">
> ## Example:<br class="">
><br class="">
> ```<br class="">
> struct TextFlags: OptionSet {<br class="">
> let rawValue: Int<br class="">
> static let italics = TextFlags(rawValue: 1 << 1)<br class="">
> static let bold = TextFlags(rawValue: 1 << 2)<br class="">
> }<br class="">
><br class="">
> let textFlags: TextFlags = [.italics, .bold]<br class="">
><br class="">
><br class="">
><br class="">
> // SWITCH STATEMENT<br class="">
> switch textFlags {<br class="">
> case let x where x.contains(.italics):<br class="">
> print("italics")<br class="">
> case let x where x.contains(.bold):<br class="">
> print("bold")<br class="">
> default:<br class="">
> print("forced to include a default case")<br class="">
> }<br class="">
> // prints "italics"<br class="">
> // Does NOT print "bold", despite .bold being set.<br class="">
><br class="">
><br class="">
><br class="">
> // MATCH STATEMENT<br class="">
> match textFlags {<br class="">
> case let x where x.contains(.italics):<br class="">
> print("italics")<br class="">
> case let x where x.contains(.bold):<br class="">
> print("bold")<br class="">
> }<br class="">
> // prints "italics"<br class="">
> // prints "bold"<br class="">
> ```<br class="">
><br class="">
> ## Enum vs. OptionSet<br class="">
><br class="">
> The basic difference between `switch` and `match` is the same conceptual difference between `Emum` and an `OptionSet` bitmask.<br class="">
><br class="">
> `switch` is essentially designed for enums: switching to a single logical branch based on the single distinct case represented by the enum.<br class="">
><br class="">
> `match` would be designed for OptionSet bitmasks and similar constructs. Executing behavior for *any and all* of the following cases and patterns that match.<br class="">
><br class="">
> 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.<br class="">
><br class="">
> ## Existing Alternatives<br class="">
><br class="">
> `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.<br class="">
><br class="">
> Example using a string of independent `if case` statements:<br class="">
><br class="">
> ```<br class="">
> if case let x = textFlags, x.contains(.italics) {<br class="">
> print("italics")<br class="">
> }<br class="">
><br class="">
> if case let x = textFlags, x.contains(.bold) {<br class="">
> print("bold")<br class="">
> }<br class="">
> ```<br class="">
><br class="">
> ## `match` statement benefits:<br class="">
><br class="">
> - Allow filtering a single object through *multiple* cases of pattern matching, executing *all* cases that match.<br class="">
><br class="">
> - A syntax that exactly aligns with the familiar, succinct, elegant, and understandable `switch` syntax.<br class="">
><br class="">
> - The keyword "match" highlights that pattern matching will occur. Would be even better than `switch` for initial introductions to pattern-matching.<br class="">
><br class="">
> - 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) {`<br class="">
><br class="">
> - 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."<br class="">
><br class="">
> - A single `match controlExpression` at the top rather than `controlExpression` being repeated (and possibly changed) in every single `if case` statement.<br class="">
><br class="">
> - 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.<br class="">
><br class="">
> - 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.<br class="">
><br class="">
> ```<br class="">
> match value { case pattern:<br class="">
> print("matched")<br class="">
> }<br class="">
> ```<br class="">
><br class="">
> - 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.)<br class="">
><br class="">
> ## Prototype<br class="">
><br class="">
> 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:<br class="">
><br class="">
> ```<br class="">
> match: for eachCase in 0...1 {<br class="">
> switch (eachCase, textFlags) {<br class="">
> case (0, let x) where x.contains(.italics):<br class="">
> print("italics")<br class="">
> case (1, let x) where x.contains(.bold):<br class="">
> print("bold")<br class="">
> default: break }<br class="">
> }<br class="">
><br class="">
> // prints "italics"<br class="">
> // prints "bold"<br class="">
> ```<br class="">
><br class="">
> ## Notes / Discussion:<br class="">
><br class="">
> - 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!<br class="">
><br class="">
> - 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.<br class="">
><br class="">
> - FizzBuzz using proposed Swift `match` statement:<br class="">
><br class="">
> ```<br class="">
> for i in 1...100 {<br class="">
> var output = ""<br class="">
> match 0 {<br class="">
> case (i % 3): output += "Fizz"<br class="">
> case (i % 3): output += "Buzz"<br class="">
> default: output = String(i)<br class="">
> }<br class="">
><br class="">
> print(output)<br class="">
> }<br class="">
><br class="">
> // `15` prints "FizzBuzz"<br class="">
> ```<br class="">
> _______________________________________________<br class="">
> swift-evolution mailing list<br class="">
> <a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
<br class="">
</blockquote></div></div>
</div></blockquote></div><br class=""></div></body></html>