Currently `if case let (foo?, bar?, baz?) = (_foo(), _bar(), _baz())`, and _bar() returns nil, then `_baz()` will not be evaluated.
On Mon, Jun 13, 2016 at 2:54 AM, Xiaodi Wu via swift-evolution < [email protected]> wrote: > What's the behavior currently with `if case let (foo?, bar?, baz?)...`? > > On Sun, Jun 12, 2016 at 19:53 plx via swift-evolution < > [email protected]> wrote: > >> This proposal should specify if the tuple is evaluated “eagerly” or as an >> “early-exit”. >> >> That is, if we write `if let (foo,bar,baz) = (_foo(), _bar(), _baz())`, >> and _bar() -> nil, will `_baz()` have been evaluated, or not? >> >> I’d use this feature either way, but the proposal should have a clear >> statement on this point. >> >> On Jun 12, 2016, at 6:46 AM, Brent Royal-Gordon via swift-evolution < >> [email protected]> 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 <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 >> [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 > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
