On Sat, Nov 18, 2017 at 3:12 PM, Peter Kamb <[email protected]> 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 <[email protected]> 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 < >> [email protected]> 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 < >>> [email protected]> 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 >>> > [email protected] >>> > https://lists.swift.org/mailman/listinfo/swift-evolution >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >> >> >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
