[swift-evolution] Idea: Extend "guard" to try-statements, with a catch block

Chris Lattner clattner at apple.com
Wed Mar 9 22:32:14 CST 2016


> On Mar 8, 2016, at 11:37 AM, Jacob Bandes-Storch <jtbandes at gmail.com> wrote:
> 
> Thanks for the feedback, Chris.
> 
> To clarify, are you suggesting that plain variable bindings would support this too (such as "let x = try foo() catch { ... }”)?

I was responding to this in your original proposal:

    // func foo() throws -> T ...
    guard let x = try foo catch {

This is inconsistent with what we currently have, because “if let” and “guard let” match against an optional and succeed iff the optional is present.  You were seemingly saying that the presence of “catch” later in the statement would affect this very primitive behavior that we have.

I’m not a strong believer in this proposal, because it is adding complexity and sugar, but I haven’t seen strong motivation that it is common.  This isn’t to say that it isn’t common and worthwhile, just that I haven’t seen any evidence.

> I like this idea. I can also foresee the desire for something like this:
> 
>     let x = try foo() catch {
>         print(error)
>         x = bar()   // by some syntax, provide a fallback value for x, since foo() threw
>         // control flow *can* escape, since x has a value
>     }

We wouldn’t do that though, we’d require guard-like behavior for the same reason we require it for guard: the value of guard is that you *know* that an instance of guard doesn’t fall through, without analyzing its behavior in depth.

> Of course, you can achieve this today

Yes, your proposal is a sugar proposal.

> with "let x; do { x = try foo() } catch { x = bar() }", or with "let x = try? foo() ?? bar()". I just wonder if it's worth considering the possibility that this new feature would allow control flow to escape in some cases. (After all, control flow can exit the "catch" block we have today.) But it's also nice to be able to glance at the code and see that, unambiguously, control flow can't escape the block.
> 
> The reason I originally suggested "guard" is readability: Seeing the word "guard", a reader knows that control flow can't escape the else/catch block. But I understand why guard is still necessary for working with optionals/patterns, and I suppose seeing "try" introducing the expression may be enough.

This shouldn’t be tied to the presence of try, because it already means something (that the enclosed expression can throw).  This:

guard let x = try foo() …

Already means “call foo, if it throws, propagate the error.  If not, test the returned optional”.  Changing that based on a subsequent ‘catch’ seems wrong.

> Another question: should it work with expressions that don't bind variables? Simply "try foo() catch { ... }" ?  (At one point I had considered "do try ... catch ...", as a braceless analogue of "do { try ... } catch ...”.)

In my opinion, this whole proposal could be better served with library functions.

-Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160309/d214701c/attachment.html>


More information about the swift-evolution mailing list