I think because it's not immediately obvious with multiple if statement, that they all try to compare the same expression to different patterns.
match exp { case 1 case 2 } vs if case 1 = exp if case 2 = anotherexp On Sat, Nov 18, 2017 at 10:43 PM, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote: > On Sat, Nov 18, 2017 at 3:12 PM, Peter Kamb <peterk...@gmail.com> wrote: > >> A high bar for new syntax is fair and expected, and by posting I was >> hoping to maybe find an alternative in the comments here. >> >> But AFAIK there's currently no ability in Swift to: >> >> "Evaluate a *single* control expression against all of these patterns, >> and execute any and all cases that match" >> >> Multiple `if-case` statements, each re-stating the control expression, >> are ok. >> >> But that's definitely not as clear or concise as a switch-like construct >> with the single control expression at the top. Or perhaps some other >> alternative such as the mentioned `continue` or somehow enumerating a set >> of cases. >> > > You're simply restating your proposed new syntax as the thing that's > missing. But what is the use case that motivates this construct? In what > way are multiple if-case statements "not as clear"? > > On Sat, Nov 18, 2017 at 11:18 AM, Xiaodi Wu <xiaodi...@gmail.com> wrote: >> >>> Robert is quite right--I'm not sure what we're designing for here. >>> There's a very high bar for introducing new syntax and a distaste for the >>> existing syntax is not a motivating use case. >>> >>> >>> On Sat, Nov 18, 2017 at 12:53 PM, Kevin Nattinger via swift-evolution < >>> swift-evolution@swift.org> wrote: >>> >>>> 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 >>>> >>> >>> >> > > _______________________________________________ > 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