It takes reaching the last section of the proposal to understand that there is 
not real issue, that it does not add any functionality, and that it basically 
amount to stylistic preference for something. It might be more informative to 
start with that rather than leave it until the end.

> On Jun 12, 2016, at 8:04 PM, Xiaodi Wu via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>> On Sun, Jun 12, 2016 at 6:46 AM, Brent Royal-Gordon via swift-evolution 
>> <swift-evolution@swift.org> 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.
>> Tuple-Based Compound Optional Binding
>> Proposal: TBD
>> Author: Brent Royal-Gordon
>> Status: TBD
>> Review manager: TBD
>> 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
>> 
>> 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 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>)')
>> 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.
>> 
>> 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).
>> 
>> Edge cases
>> 
>> 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 { ... }
>> 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.
>> 
> 
> I think this proposal is definitely worthy of consideration (and 
> implementation). I hesitate that what works or not is being proposed partly 
> on the basis of whether it's difficult to implement or not. If I could offer 
> a suggestion as to exactly which edge cases should work, I think it should be 
> based on this guideline that can be articulated cleanly:
> 
> Given `if let (a, b, c)...` or any other variation or edge case, transform in 
> your mind's eye to `if case let (a?, b?, c?)...`. That is, append `case` 
> before `let` and then append `?` immediately after each constant so 
> introduced. If the `if case let...` version would work, so should the `if 
> let...` version. By that rule of thumb, `if case let (a?, (b?, c?)) = (opt1, 
> (opt2, opt3))` would work if I'm not mistaken, as would `if case let (a?, b?) 
> = tuple`, but `if case let tuple? = (opt1, opt2)` would not and thus neither 
> should `if let tuple = (opt1, opt2)`.
>  
>> 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.
>> 
>> 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 { ... }
>> Alternatives Considered
>> 
>> 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.
>> 
>> 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
> 
> _______________________________________________
> 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

Reply via email to