<div dir="ltr"><div>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:<br></div><div><br></div><div>    // func foo() -&gt; T? ...</div><div>    guard let x = foo() <b>else</b> {</div><div>        // the compiler does not allow control flow to escape this block</div><div>    }</div><div>    // control flow cannot reach here if foo() returned nil</div><div><br></div><div>Guard statements can be used with the optional form &quot;<b>try?</b>&quot; to provide the same functionality for throwing functions:</div><div><br></div><div>    // func foo() throws -&gt; T ...</div><div>    guard let x = <b>try?</b> foo() <b>else</b> {<div>        // the compiler does not allow control flow to escape this block</div>        // the &quot;error&quot; parameter is not available here<div>    }</div><div>    // control flow cannot reach here if foo() threw an error</div><br></div><div>However, the error that was thrown is not recoverable inside the &quot;else&quot; block. A workaround is to add extra lines of code &amp; indentation levels to achieve this with do+catch:</div><div><br></div><div>    let x: T</div><div>    do {<br>        x = try foo()</div><div>    } catch {</div><div>        // control flow can escape this block, but the compiler won&#39;t allow x to be used later if it&#39;s not initialized here</div><div>    }</div><div><br></div><div><b>I propose extending guard-statements to handle errors</b> without using the optional &quot;try?&quot; and without a do-block, by allowing the expression to throw, and offering &quot;catch&quot; instead of &quot;else&quot;:</div><div><br></div><div>    // func foo() throws -&gt; T ...</div><div>    guard let x = <b>try</b> foo <b>catch</b> {</div><div>        print(&quot;the error was: \(<b>error</b>)&quot;)  // the &quot;error&quot; parameter is available here</div>        // the compiler does not allow control flow to escape this block<div>    }</div>    // control flow cannot reach here if foo() threw an error<div><br></div><div>We could allow the same sorts of catch blocks as normal do-blocks:</div><div><br></div><div>    guard let x = try foo() <b>catch let error as MyErrorType</b> {</div><div>        // handle specific error; control flow must not escape<br>    } <b>catch</b> {</div><div>        // fallback error case; control flow must not escape</div><div>    }<br><div><div><br></div><div>(Of course, we&#39;d want to offer sensical error message / fix-it hints when &quot;else&quot; was used with a throwing statement, or when &quot;catch&quot; was used with a non-throwing statement.)</div><div><br></div>Thoughts?</div><div><br></div><div>Here are some discussion topics:</div><div><br></div><div>- If Swift&#39;s error-handling mechanisms evolved into a first-class Result type, would this proposal be moot?</div><div><br></div><div>- Would this make sense as a feature of pattern-matching, rather than just &quot;guard&quot;, so you could also do &quot;if case let x = try foo() { ... } catch { ... }&quot; ?</div><div><br clear="all"><div><div><div dir="ltr"><div>Jacob<br></div></div></div></div>
</div></div></div>