The problem is that currently the if-let and guard-let syntax is reserved for 
unwrapping optionals and therefore cannot be used (at least not unambiguously) 
for simple let-bindings as well, which is required here.

My example therefore needs the following change (sorry, I did not make this 
explicit):

1. allow let-bindings in if- and guard-statements and
2. require explicit optional unwrapping by pattern matching in if- and 
guard-statements

In addition I’d like to add the following (but that’s really a separate 
proposal):
3. drop the „case“ keyword for pattern matching

The example would then look like follows (written in multiple lines for adding 
comments):

guard 
     let r = returnsResult(),   // simple let-binding
     let .Succeed(m) = r                // pattern matching
else {
     return r 
}

Unwrapping optionals would then look like follows (i.e. no special syntax for 
unwrapping optionals):

if let .Some(x) = x {
        …
}

A shorter alternative might be: if let x ?= x { … }

IIRC this or something similar was part of an earlier Swift release and was 
streamlined to the current syntax because optionals are quite common and 
already have special syntax sugar. The problem is that the current syntax while 
being convenient for its succinctness is ambiguous with simple let-bindings 
which is inconsistent and - more importantly - makes extending if-statements 
and guard-statements by simple let-bindings impossible.

-Thorsten


> Am 24.12.2015 um 18:13 schrieb Félix Cloutier <[email protected]>:
> 
> Wait, no, there's a problem with that. You can't use `r` in the guard scope 
> because `returnsResult()` might not have succeeded.
> 
> Félix
> 
>> Le 24 déc. 2015 à 09:37:36, Félix Cloutier via swift-evolution 
>> <[email protected]> a écrit :
>> 
>> I like that it's consistent with the if syntax (even though I don't really 
>> like the if syntax) and that there's no dangling parts after the else.
>> 
>> Félix
>> 
>>> Le 24 déc. 2015 à 06:29:17, Thorsten Seitz via swift-evolution 
>>> <[email protected]> a écrit :
>>> 
>>> What do you think of
>>> 
>>> guard let r = returnsResult(), case let .Succeed(m) = r else {
>>>      return r 
>>> }
>>> 
>>> Which binds r only within the scope of the guard as desired.
>>> 
>>> Written in multiple lines
>>> 
>>> guard 
>>>      let r = returnsResult(), 
>>>      case let .Succeed(m) = r 
>>> else {
>>>      return r 
>>> }
>>> 
>>> -Thorsten 
>>> 
>>>> Am 24.12.2015 um 01:02 schrieb Andrew Duncan via swift-evolution 
>>>> <[email protected]>:
>>>> 
>>>> Yes, which would revert to Brent’s suggestion. But you have generalized it 
>>>> in a very compatible way.
>>>> 
>>>> As I read somewhere, improving programming languages comes from removing 
>>>> limitations rather than adding features. I intend for this Pitch to be the 
>>>> former, although it does kind of look like the latter.
>>>> 
>>>>> On 23 Dec, 2015, at 15:58, Joe Groff <[email protected]> wrote:
>>>>> 
>>>>> 
>>>>>> On Dec 23, 2015, at 3:56 PM, Andrew Duncan <[email protected]> 
>>>>>> wrote:
>>>>>> 
>>>>>> More progress! This sounds good, but it looks like what you intend is 
>>>>>> for r to be the error message in the Result enum type.
>>>>>> 
>>>>>> enum Result {
>>>>>> case .Fail(String)    // Error message
>>>>>> case .Succeed(MyType) // Something to work with
>>>>>> }
>>>>>> 
>>>>>> guard case let .Succeed(m) = returnsResult() else case let .Failure(r) {
>>>>>> return r // Looks like r is bound to the error String. 
>>>>>>          // But maybe you meant r = the entire returnsResult() result.
>>>>>> }
>>>>> 
>>>>> I see. If it's an arbitrary pattern, you can match 'case let r' to bind 
>>>>> the entire value instead of picking out the payload of the other case. 
>>>>> That would still be exhaustive.
>>>>> 
>>>>> -Joe
>>>>> 
>>>>>> 
>>>>>> The sort of message-passing error-handling I have in mind is where each 
>>>>>> method in the call chain returns a full Result enum and each stage 
>>>>>> checks it for Succeed/Fail, and immediately bails on Fail, returning 
>>>>>> (propagating) the Result. To be sure, this is sort of what exceptions do 
>>>>>> under the hood anyway.
>>>>>> 
>>>>>> My use-case is a recursive descent parser that I want to bail when a 
>>>>>> syntax error is found. This could happen way deep in the stack of calls. 
>>>>>> If I consistently return a .Fail(ErrorCode) or .Succeed(ASTNode) from 
>>>>>> each method, I just pass on the Result in case of .Fail, or use it in 
>>>>>> case of .Succeed.
>>>>>> 
>>>>>> 
>>>>>>> On 23 Dec, 2015, at 15:35, Joe Groff <[email protected]> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>>> On Dec 23, 2015, at 10:16 AM, Andrew Duncan via swift-evolution 
>>>>>>>> <[email protected]> wrote:
>>>>>>> 
>>>>>>> A slight generalization would be to allow for an arbitrary pattern in 
>>>>>>> the `else` clause:
>>>>>>> 
>>>>>>> guard case let .Succeed(m) = returnsResult() else case let .Failure(r) {
>>>>>>> return r
>>>>>>> }
>>>>>>> 
>>>>>>> with the requirement that the "guard" and "else" patterns form an 
>>>>>>> exhaustive match when taken together. That feels nicer than 
>>>>>>> special-case knowledge of two-case enums, though I admit it punishes 
>>>>>>> what's likely to be a common case.
>>>>>>> 
>>>>>>> -Joe
>>>> 
>>>> _______________________________________________
>>>> 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

Reply via email to