> On Jun 12, 2016, at 4:46 AM, Brent Royal-Gordon <br...@architechies.com> 
> wrote:
> 
> When I suggested this syntax in the acceptance thread for SE-0099, Chris said 
> it should be written up as a proposal. I'm sure this will get lost in the 
> WWDC shuffle, but here goes.

Hi Brent,

I’m sorry that I haven’t had time yet to read the down thread responses, but I 
don’t see how this can work:


“if let pattern = expr” is sugar for “if case let pattern? = expr”, so this 
would either:

a) only apply to tuple literals on the right side or
b) not work, since this syntax above already means “if case let (a,b,c)? = 
expr”.

If you pick a, then it is makes tuple literals inconsistent with other 
expressions, which seems to make the language more confusing and less 
orthogonal.

-Chris





> Tuple-Based Compound Optional Binding
> Proposal: TBD
> Author: Brent Royal-Gordon <https://github.com/brentdax>
> Status: TBD
> Review manager: TBD
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#introduction>Introduction
> 
> This proposal enhances optional binding with a new, tuple-based syntax for 
> binding multiple values. It replaces functionality lost in SE-0099 with a 
> syntax compatible with the new design.
> 
> Swift Evolution Discussion: [Accepted with Revision] SE-0099 Restructuring 
> Condition Clauses 
> <http://thread.gmane.org/gmane.comp.lang.swift.evolution/19452/focus=20139>
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#motivation>Motivation
> 
> In Swift 2, it was possible to bind multiple optional values in a single if 
> let, guard let, or while let clause:
> 
> guard let a = opt1, b = opt2, c = opt3 else { ... }
> SE-0099 
> <https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md>
>  simplified the syntax of conditional statements, but removed this feature so 
> that , could instead separate different conditional clauses. Code like this 
> must now use three separate optional binding clauses:
> 
> guard let a = opt1, let b = opt2, let c = opt3 else { ... }
> The similar case clause sidesteps this problem because it can pattern-match 
> tuples. Hence, you can put several patterns in a tuple on the left side of 
> the =, and a matching number of values in a tuple on the right side, and 
> match them all with one case clause:
> 
> guard case (.none, .none, .none) = (opt1, opt2, opt3) else { ... }
> This doesn't conflict with the clause separation syntax because the commas 
> are within parentheses. However, the analogous syntax for optional bindings 
> is not permitted:
> 
> guard let (a, b, c) = (opt1, opt2, opt3) else { ... }
> // error: initializer for conditional binding must have 
> // Optional type, not '(Int?, Int?, Int?)' (aka 
> // '(Optional<Int>, Optional<Int>, Optional<Int>)')
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#proposed-solution>Proposed
>  Solution
> 
> We should extend optional binding clauses to permit a tuple of optional 
> values on the right of the = and a tuple of constants with identical arity on 
> the left. Swift should test each element of the tuple on the right, and if 
> none of them are nil, bind them to the constants on the left.
> 
> Nothing in this proposal should change the way optional binding handles an 
> optional tuple (T, U)?, as opposed to a tuple of optionals (T?, U?). Even an 
> optional tuple of optionals (T?, U?)? should continue to be handled as before.
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#detailed-design>Detailed
>  Design
> 
> No change to the formal grammar is necessary, as the pattern and initializer 
> productions in the optional-binding-head rule can already match tuples:
> 
> optional-binding-head : 'let' pattern initializer
> Rather, Sema should be modified to detect this situation and generate 
> appropriate code. Currently, TypeCheckPattern.cpp essentially converts let a 
> = opt1 into case let a? = opt1; if this proposal is accepted, it should 
> similarly convert let (a, b) = (opt1, opt2) into case let (a?, b?) = (opt1, 
> opt2).
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#edge-cases>Edge
>  cases
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#nested-tuples-of-optionals>Nested
>  tuples-of-optionals
> 
> Permitting deeper pattern matching of nested tuples is highly precedented by 
> pattern matching, but is a niche feature. It should be supported if easily 
> achievable.
> 
> guard let (a, (b, c)) = (opt1, (opt2, opt3)) else { ... }
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#expressions-returning-tuples-of-optionals>Expressions
>  returning tuples of optionals
> 
> Ideally, optional bindings whose initializer is an expression evaluating to a 
> tuple of optionals would be supported:
> 
> let tuple = (opt1, opt2)
> if let (a, b) = tuple { ... }
> However, I'm not sure if Swift will have pinned down the type of the 
> initializer at the point where it's generating the pattern. If this would be 
> difficult or impossible to implement, Swift should continue to interpret code 
> like this as attempting to bind an optional tuple, rather than a tuple of 
> optionals.
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#single-name-patterns>Single-name
>  patterns
> 
> In theory, Swift could allow you to bind a tuple of optionals to a single 
> constant:
> 
> if let tuple = (opt1, opt2) { ... }
> However, this seems error-prone; the pattern doesn't draw a very clear 
> picture of the value being operated upon, so you could easily misinterpret it 
> as binding an optional tuple. Because of this ambiguity, Swift should always 
> interpret this construct as binding an optional tuple, rejecting it with a 
> type error if necessary.
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#impact-on-existing-code>Impact
>  on Existing Code
> 
> This proposal is additive compared to SE-0099, but in combination with it, 
> essentially replaces the Swift 2.2 compound binding syntax with a different, 
> incompatible one. When moving directly from Swift 2.2, the migrator should 
> convert old-style compound optional binding clauses:
> 
> guard let a = opt1, b = opt2, c = opt3 else { ... }
> Into the new, tuple-based ones:
> 
> guard let (a, b, c) = (opt1, opt2, opt3) else { ... }
> The "one-let-per-binding" syntax remains compatible with both Swift 2.2 and 
> Swift 3, so projects which must support both can still perform multiple 
> optional bindings in a single if statement without resorting to an #if 
> swift(>=3.0) build configuration:
> 
> guard let a = opt1, let b = opt2, let c = opt3 else { ... }
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#alternatives-considered>Alternatives
>  Considered
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#not-accepting-this-proposal>Not
>  accepting this proposal
> 
> This proposal does not add new functionality; it merely removes keyword 
> clutter. However, it offers a convenient replacement for a commonly-used 
> feature which has just been removed as a result of grammatical ambiguity, not 
> user confusion or lack of utility.
> 
>  
> <https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#providing-similar-standard-library-functionality>Providing
>  similar standard library functionality
> 
> Rather than including this functionality in the compiler, the standard 
> library could provide a series of functions like:
> 
> public func all<T, U>(_ t: T?, _ u: U?) -> (T, U)? { ... }
> public func all<T, U, V>(_ t: T?, _ u: U?, _ v: V?) -> (T, U, V)? { ... }
> // etc.
> These could then be used in a similar fashion to this proposal:
> 
> guard let (a, b, c) = all(opt1, opt2, opt3) else { ... }
> However, because we do not have variadic generics, we would need to provide a 
> set of overloads for different arities, and our support would be limited to 
> the arities we chose to provide. (Support for tuples, as opposed to separate 
> parameters, would require a second set of overloads). Meanwhile, the tuple 
> matching syntax is already precedented in case conditionals, so extending it 
> seems pretty natural. Providing this in the compiler seems like the right 
> solution.
> 
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to