I suggest you split this into 2 separate proposals. The second part seems much, much more controversial than the first.
Cheers, Jaden Geller > On Feb 28, 2017, at 11:01 AM, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote: > > The following draft proposal addresses one matter of substance (eliminating > edge case errors by adopting at-site conditional binding) and one of style > (using the pattern match operator consistently). Its discussion was deferred > from Phase 1 and remains in a fairly early stage. Your feedback will help me > decide whether this is a proposal I want to keep developing or one that I > should set aside and focus on other matters. Thank you. -- E > > The work-in-progress gist is here: > https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c> > > Simplifying case syntax > > Proposal: TBD > Author: Erica Sadun <https://github.com/erica> > Status: TBD > Review manager: TBD > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#introduction>Introduction > > This proposal re-architects case syntax grammar to reduce potential errors > and simplify unwrapping enumerations. > > Swift-evolution thread: [Pitch] ReimaginingĀ guard case/if case > <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161024/tbd.html> > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#motivation>Motivation > > In its current design, Swift case binding suffers from two weaknesses. > > Mixed external and internal let/var binding may introduce errors from > uncommon edge cases. > Real-world users may not consider the parallel construction between if > case/guard case with switchstatements or naturally connect the two layouts. > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#internal-case-binding>Internal > Case Binding > > When pattern matching, it's common to bind a variable or constant. It's > uncommon but legal to use a bound value as an argument. Adopting an "always > explicit, always within the parentheses" rule adds consistency and safety to > Swift. > > Consider the following enumeration and values: > > // An enum with one, two, or three associated values > enum Value<T> { case one(T), two(T, T), three(T, T, T) } > > // An example with two associated values > let example2: Value<Character> = .two("a", "b") > > // A bound symbol > let oldValue = "x" > This code's goal is to conditionally bind newValue and pattern match the > value stored in the oldValue symbol. The first example succeeds. The second > example compiles and runs but does not match the coder's intent. Using an > external letcreates a new oldValue shadow instead of pattern matching > oldValue's stored value. > > // Safe > if case .two(let newValue, oldValue) = example2 { > ... > } > > // Syntactically legal but incorrect > if case let .two(newValue, oldValue) = example2 { > ... > } > In-parenthesis binding avoids accidental shadowing. It eliminates this class > of error by adding let and var key words to each use point. This creates > longer call sites but enumerations rarely contain more than three or four > associated items. > > Adopting point-of-use binding enhances clarity and readability. Both if case > let and if case var (plus case varand case let) may look like single compound > keywords rather than a combination of two distinct actions to developers > unfamiliar with this syntax. > > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#pattern-matching-with-conditional-binding>Pattern > Matching with Conditional Binding > > Swift's guard case and if case align statement design with the switch > statement, moving the matched value to the right of an equal sign. > > switch value { > case .enumeration(let embedded): ... > } > > if case .enumeration(let embedded) = value > The status quo for the = operator is iteratively built up in this fashion: > > = performs assignment > let x = performs binding > if let x = performs conditional binding on optionals > if case .foo(let x) = performs conditional binding on enumerations and > applies pattern matching > Using if case/guard case in the absense of conditional binding duplicates > basic pattern matching with less obvious meaning. These two statements are > functionally identical: > > if range ~= myValue { ... } // simpler > if case range = myValue { ... } // confusing > Issues with the current design include: > > guard case and if case look like standard non-conditional assignment > statements but they are not assignment statements. Using the assignment > operator violates the principle of least astonishment > <https://en.wikipedia.org/wiki/Principle_of_least_astonishment>. > In switch, a case is followed by a colon, not an assignment operator. > Swift has a pattern matching operator (~=) but does not use it here. > case syntax is wordy. The statement includes case, =, and optionally let/var > conditional binding. Design alternatives could streamline this syntax, > enhance clarity, and introduce a more concise format. > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#detailed-design>Detailed > Design > > This proposal adopts point-of-use conditional binding and recommends one of > the following designs. A successful design will replace the current syntax > with a simpler grammar that prioritizes pattern matching and support > conditional binding. > > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#design-1-using-the-pattern-matching-operator>Design > 1: Using the Pattern Matching Operator > > This design drops the case keyword and replaces = with ~=. The results look > like this, showcasing a variety of letplacement, variable binding, and > optional sugar alternatives. > > guard .success(let value) ~= result else { ... } > guard .success(var value) ~= result else { ... } > if .success(let value) ~= result { ... } > if .success(var value) ~= result { ... } > guard let x? ~= anOptional else { ... } > if let x? ~= anOptional { ... } > In this design: > > The case keyword is subsumed into the (existing) pattern matching operator > The statements adopt the existing if-let/if var and guard-let/guard var > syntax, including Optionalsyntactic sugar. > if let x = anOptional { ... } // current > > if case let x? = anOptional { ... } // would be removed > if let x? ~= anOptional { ... } // proposed replacement for `if case` > Pattern matching without conditional binding simplifies to a standalone > Boolean condition clause. On adopting this syntax, the two identical range > tests naturally unify to this single version: > > if range ~= myValue { ... } // before > if case range = myValue { ... } // before > > if range ~= myValue { ... } // after > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#design-2-using-a-declare-and-assign-operator>Design > 2: Using a Declare and Assign Operator > > This design introduces new := "declare and assign" operator. This operator > eliminates the need for explicit let, although the keyword is allowed and > most house style guides would recommend its use: > > guard .success(value) := result else { ... } > guard .success(let value) := result else { ... } > if .success(value) := result { ... } > if .success(let value) := result { ... } > guard value? := anOptional else { ... } // newly legal, although unnecessary > guard let value? := anOptional else { ... } // newly legal, although > unnecessary > Assignments to variables require the var keyword, enabling coders to clarify > the distinct roles in mix-and-match pattern matching: > > guard .pair(value1, var value2) := result else { ... } // implied let > guard .pair(let value1, var value2) := result else { ... } // explicit let > if .success(var value) := result { ... } // variable assignment > guard var x? := anOptional else { ... } // variable assignment > guard var x := anOptional else { ... } // simpler variable assignment > guard var x = anOptional else { ... } // even simpler (current) variable > assignment > guard x := anOptional else { ... } // new constant assignment > Adopting this syntax provides more natural results for binding associated > enumeration variables. > > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#excluded-from-this-proposal>Excluded > from this proposal > > This proposal does not address switch case or for case beyond internal > binding requirements. > > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#impact-on-existing-code>Impact > on Existing Code > > This proposal is breaking and would require migration. External let or var > would automatically be moved by fixits into use points. Current guard case > and if case syntax would be migrated to the new design. > > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#timeline>Timeline > > Although removing if case and guard case are breaking, this proposal should > wait until Swift 4 Stage two to allow proper debate and consideration from > the core team. > > > <https://gist.github.com/erica/06dad9bbe1a70290fe6b89a64f73bc0c#alternatives-considered>Alternatives > Considered > > Leaving the grammar as-is, albeit confusing > Retaining case and replacing the equal sign with ~= (pattern matching) or : > (to match the switch statement). > Adding matches or is as an alternative to the pattern matching operator > > _______________________________________________ > 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