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

Jacob Bandes-Storch jtbandes at gmail.com
Mon Feb 29 14:09:52 CST 2016


Guard statements interact with pattern-matching to ensure that control flow
cannot continue unless a pattern is matched. This is a very convenient way
to introduce non-optional variables from optional-valued expressions:

    // func foo() -> T? ...
    guard let x = foo() *else* {
        // the compiler does not allow control flow to escape this block
    }
    // control flow cannot reach here if foo() returned nil

Guard statements can be used with the optional form "*try?*" to provide the
same functionality for throwing functions:

    // func foo() throws -> T ...
    guard let x = *try?* foo() *else* {
        // the compiler does not allow control flow to escape this block
        // the "error" parameter is not available here
    }
    // control flow cannot reach here if foo() threw an error

However, the error that was thrown is not recoverable inside the "else"
block. A workaround is to add extra lines of code & indentation levels to
achieve this with do+catch:

    let x: T
    do {
        x = try foo()
    } catch {
        // control flow can escape this block, but the compiler won't allow
x to be used later if it's not initialized here
    }

*I propose extending guard-statements to handle errors* without using the
optional "try?" and without a do-block, by allowing the expression to
throw, and offering "catch" instead of "else":

    // func foo() throws -> T ...
    guard let x = *try* foo *catch* {
        print("the error was: \(*error*)")  // the "error" parameter is
available here
        // the compiler does not allow control flow to escape this block
    }
    // control flow cannot reach here if foo() threw an error

We could allow the same sorts of catch blocks as normal do-blocks:

    guard let x = try foo() *catch let error as MyErrorType* {
        // handle specific error; control flow must not escape
    } *catch* {
        // fallback error case; control flow must not escape
    }

(Of course, we'd want to offer sensical error message / fix-it hints when
"else" was used with a throwing statement, or when "catch" was used with a
non-throwing statement.)

Thoughts?

Here are some discussion topics:

- If Swift's error-handling mechanisms evolved into a first-class Result
type, would this proposal be moot?

- Would this make sense as a feature of pattern-matching, rather than just
"guard", so you could also do "if case let x = try foo() { ... } catch {
... }" ?

Jacob
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160229/fbf66a7d/attachment.html>


More information about the swift-evolution mailing list