Thanks for you considerate reply. My concern over the proliferation of “sugar 
proposals” is a general one. This proposal has more merit and general utiliity 
than many others. I have never used a throwing function in a guard statement 
that was not itself in a throwing function, but I can see that it could 
possibly be common in some code. Wrapping a guard statement and all the code 
that uses variables set in the guard in a do/catch is sub-optimal.

> On Jul 8, 2017, at 4:16 PM, Benjamin Spratling via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 
>> On Jul 8, 2017, at 4:08 PM, Christopher Kornher <ckorn...@me.com> wrote:
>> 
>> I am opposed to this proposal because it muddies up the language to support 
>> what is essentially an edge case. The standard way to exit a function early 
>> because an exception is thrown is to make the function itself throw, if it 
>> is part of a larger operation. The addition of a few lines of try/catch code 
>> is not a great burden and makes the termination of an an exception very 
>> clear.
> 
> I’ve read your email, but haven’t digested it fully.  One thing I agree with 
> is that most functions which call throwing functions don’t actually use a 
> do…catch block, but instead are merely marked “throws” and the error is 
> propagated back through the stack.  Once I seriously started coding functions 
> with errors, I realized I almost always wanted my errors to reach my 
> view-controller or my business logic so I could present separate UI if a real 
> error occurred, and often my error message depended on the details of the 
> error instance.
> 
>> `guard` statements are generally used to set variables that are needed in 
>> the body of a function. Using them to save a few lines of exception handing 
>> code is a very different use. There is no need to mix two relatively clean 
>> syntaxes for a few edge cases and increase cognitive load one more time, 
> 
> 
> I disagree with your conclusion on this point.
> The “guard” syntax is specifically designed to achieve early return (and 
> placing code associated with early return at the point where it happens) and 
> cleanly installing the returned value into the surrounding scope.  So far it 
> has been used to achieve early return only with optionals, true.  But is that 
> inherent to ‘guard’, or is it merely because that’s the only way it has been 
> used?  The guard does set variables that are needed in the body of the 
> function, and that’s exactly why using guard with values returned from 
> throwing functions makes so much sense, because it does exactly the same 
> thing in a general sense.  The “do”…”catch” structure is intentionally 
> designed differently, to place the “happy path” in one place and place the 
> returns in another place.  I think with guard/else, we’re seeing developers 
> who can handle less cognitive loading find it easier to reason about early 
> return than grouping failures after the happy path.  This proposal hopes to 
> introduce that better language architecture to the catching of errors.

All catches don’t have to exit the outer scope, so using guard only handles a 
subset 

It think that creating the terse try/catch for simple cases has multiple 
advantages:

        1) I think that it addresses your desire for a simple way to use 
throwing functions easily in guard statements.

        2) It avoids having to change the guard syntax to accomplish this

        3) It is useful for handling simple one line try/catch constructs in 
less space in a way that should not seem too foreign to Swift developers.
        
        4) It simplifies code that currently uses nested do/try/catch 
constructs. Even though this is rare, it introduces significant “rightward 
drift”.

        5) It can used to return early from void throwing functions easily. 
e.g. : 

        ```
        guard try foo( ) catch { return }
        ```
        
        Multiple void throwing functions would probably be better handled by a 
do/catch block, but there is no danger of needing values from these functions 
because there are none:

        ```
        do {
                try fn1()
                try fn2()
        } catch {
                // keep going, return or call a non-returning function, since 
throw is already handled by declaring a throwing enclosing function.
                // No varibles are needed by the outer block because none are 
set
                // So it is not clearly a guard-like statement
        }        
        ```

        I did not think of this before, but perhaps we could allow `do` to be 
replaced with `guard`, thereby allowing values to escape to the outer scope, 
while still ensuring an early exit:

        ```
        guard {
                try fn1()
                try fn2()
                let x = fn3()
        } catch {
                // Must exit
        } else {
                // Must exit
        }        
        ```
I am not sure that “leaky” braces are a good idea, so perhaps some other 
character could be used to indicate a non-scope or whatever you want to call it:

        ```
        guard <your favorite character here>
                try fn1()
                try fn2()
                let x = fn3()
         <another favorite character here> catch {
                // Must exit
        } else {
                // Must exit
        }        
        ```
This would make the language even harder to read, so just using braces is 
probably a better idea.

This would change the guard syntax slightly, but is a straightforward 
extrapolation of do/catch and guard, I think. Of course, this could replace the 
existing guard syntax entirely and its use of semicolons, if we want to go that 
far…

Allowing this syntax only if one of the expressions throws is possibly a good 
backward-compatible solution that would avoid redundant guard syntaxes.

Anyway there are lot of possibilities here. We are not forced to extend the 
guard statement as it exists today. The current guard statement syntax was 
quite controversial when it was introduced and extending it may not be the best 
option to do what you want.

- Chris




> 
> -Ben Spratling
> 
> _______________________________________________
> 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