> Let me answer in another way that speaks to my background which isn't in 
> compiler theory: The use of && may produce cognitive overload between the use 
> in Boolean assertions and the use in separating condition clauses.

Yes, which is quite intentional on my part. The `if` statement requires that 
all of its clauses succeed; if pattern matching and optional testing were 
boolean expressions, you would use `&&` to link them with each other and with 
boolean tests. The fact that these are *not* boolean expressions is a mere 
artifact of Swift's implementation.

I think our best solution is to make Swift act as though these *are* boolean 
expressions, but ones that can only be used in a limited way: they can only be 
`&&`ed, because they bind variables that have to be made available in specific 
blocks. In other words, I think we should paper over the compiler limitations 
preventing these things from working as expected.

(Actually, it might be interesting to allow `!let` and `!case` statements which 
are available in the `else` branches of the control structures they're used in, 
but that's a different story...)

***

If you'll permit me to go sort of "mad dream" here for a moment, I can actually 
sort of see a way to do a lot of this in the standard library. Imagine if the 
`let` and `case` clauses in a conditional produced a type like this:

        enum PatternMatchingResult<BoundValues> {
                case failed
                case succeeded (BoundValues)
        }

`BoundValues` would be the values, if any, extracted through the pattern 
matching operation. Then you could define operators like these:

        func && <T, U>(lhs: PatternMatchingResult<T>, rhs: @autoclosure () -> 
PatternMatchingResult<U>) -> PatternMatchingResult<(T, U)> {
                guard case .succeeded (let lhsValue) = lhs else {
                        return .failed
                }
                guard case .succeeded (let rhsValue) = rhs() else {
                        return .failed
                }
                return .succeeded (lhsValue, rhsValue)
        }

        func && <T>(lhs: PatternMatchingResult<T>, rhs: @autoclosure () -> 
Boolean) -> PatternMatchingResult<T> {
                guard case .succeeded = lhs else {
                        return .failed
                }
                guard rhs() else {
                        return .failed
                }
                return lhs
        }
        
        func && <U>(lhs: Boolean, rhs: @autoclosure () -> 
PatternMatchingResult<U>) -> PatternMatchingResult<U> {
                guard lhs else {
                        return .failed
                }
                return rhs()
        }

And then transform this:

        guard
                x == 0 && a == b && c == d &&
                let y = optional, w = optional2, v = optional 3 &&
                z == 2
        else { ... }

Into something like this (where `?` is a sort of "anonymous capture slot"):

        guard case let .success (y, w, v) = (
                x == 0 && a == b && c == d &&
                Pattern(.some(?), .some(?), .some(?)).result(ofMatchingAgainst: 
(optional, optional2, optional3)) &&
                z == 2
        )
        else { ... }

Resolving to:

        guard case let PatternMatchingResult.success (y, w, v) = (
                (&&)(   // (Boolean, PatternMatchingResult) -> 
PatternMatchingResult
                        x == 0,
                        (&&)(   // (Boolean, PatternMatchingResult) -> 
PatternMatchingResult
                                a == b,
                                (&&)(   // (Boolean, PatternMatchingResult) -> 
PatternMatchingResult
                                        c == d,
                                        (&&)(   // (PatternMatchingResult, 
Boolean) -> PatternMatchingResult
                                                Pattern(.some(?), .some(?), 
.some(?)).result(ofMatchingAgainst: (optional, optional2, optional3)),
                                                z == 2
                                        )
                                )
                        )
                )
        )
        else { ... }

The `Pattern` type shown here is notional, not an actual thing that would exist 
as a first-class entity—although that *would* be rather nice to have 
eventually...

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to