<div dir="ltr">On Sat, Jul 8, 2017 at 2:11 PM, Benjamin Spratling via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><span class="gmail-"><div><br></div><blockquote type="cite"><div><font face="Menlo"><span style="font-size:11px">func doSomething() throws → Result? { … }</span></font></div><div><br></div><div>How would you handle both the catch and the let binding of the result?</div></blockquote><br></span><div>I agree this proposal needs to define the behavior, since returning an optional from a throwing function is valid.</div><div><br></div><div>I see a few options:</div><div><br></div><div>1) find a way to generally incorporate optional binding and error binding into the same guard clause.</div><div>Could it be as simple as </div><div>guard let result:Result = try doSomething()</div><div>catch { ...}</div><div>else { ... }</div><div>?</div><div><br></div><div> In this option, the else block almost acts like &quot;finally&quot; block.  I recommend against this option because IF the developer has defined a function which returns nil and doesn&#39;t throw an error, they clearly intend for the nil to be a valid representation of state, and thus one the developer may wish to examine in more detail and potentially continue the function. I. E. Let&#39;s give the developer a chance to work with the nil value and not return.</div><div><br></div><div>2) Ignore it completely.  I.e. define the guard/catch pattern as not compatible with returning Optionals.  Throwing an error is usually considered an alternative to returning an optional, and importing Obj-C won&#39;t import throwing methods in this way. So I don&#39;t think prohibiting it is a totally absurd idea.  <span style="background-color:rgba(255,255,255,0)">This makes it impossible for the developer to code and build code which accidentally does something he doesn&#39;t expect.</span></div><div><br></div><div>3) bind the optional value</div><div><br></div><div>Perhaps, when guard/catch-ing, an optional value is perfectly legal.</div><div><br></div><div>guard let result:Result? = try doSomething() catch ...</div><div>This is essentially how guard works with a try?today.</div><div>guard let result:Result? = try? doSomething() ...</div><div><br></div><div>In case 3, I think we have a potentially ambiguous behavior, because with type inference the programmer may expect that the value has also been optionally unwrapped.  Of course, he&#39;ll catch that later on in the function, but my concern is for the poor unwitting developer (such as myself) who is frustrated that his code doesn&#39;t compile and he doesn&#39;t understand why.  &quot;But I did a guard let!   Why is it optional?!&quot;  One option is to require the type be typed explicitly when guard/catching an optional, but I always type my types explicitly anyway, so I get that others may be more resistant to that idea.  Another option is to allow it, but just issue a warning until the developer adds the explicit type, such as requiring &quot;self.&quot; in an escaping closure.  (Of course the compler can figure it out, this syntax is required so the developer can figure it out!)  Another option is for the smarts to be built in the the error/warning system to point out when an expression gets used as a non-optional when it came from a guard/catch to point it out, much as it points out the first instance of a function which has been defined twice.</div></div></blockquote><div><br></div><div>Agree that (3) is potentially ambiguous and has high likelihood to be a footgun.</div><div><br></div><div>Also agree that _if_ the developer defines a function that can return nil *and* can throw an error, nil is likely to be a bona fide representation of state. One possibility--with an obvious problem (see below)--is therefore to have the successful result of guard...catch be of type `Result?`:</div><div><br></div><div>```</div><div>guard let result = try doSomething() catch { ... }</div><div>guard let unwrappedResult = result else { ... }</div><div>```</div><div><br></div><div>The obvious problem is that `guard let` in Swift is closely associated with optional unwrapping. The reader is right to expect a non-optional `result` with `guard let` regardless of the word that comes after conditional expression. There are two ways to see this:</div><div><br></div><div>One way is: If we consider `doSomething() throws -&gt; Result?` to be a function where throwing indicates that the operation has failed and nil is a bona fide representation of state, then it can be seen as a function more similar to `doSomethingElse() -&gt; Result??`, where the outer Optional indicates whether the operation succeeded (see Swift error handling rationale document) and the inner Optional is a bona fide representation of state. Therefore, just as `guard let result = doSomethingElse() else { ... }` gives you a result of type `Result?`, so should `guard let result = try doSomething() catch { ... }`.</div><div><br></div><div>However, I can see how this might be confusing to users. The fundamental problem here is one of spelling, where users instinctively see `guard let` and expect one level of optional unwrapping. This idea is reinforced because `guard...else` does *not* permit `guard let` when the result isn&#39;t optional. Therefore, another way to solve this issue is to make this rule also apply to `guard...catch`. That is, make the syntax of `guard...catch` _not_ use `guard let` unless the result is optional:</div><div><br></div><div>```</div><div>let result: Result?</div><div>guard result = try doSomething() catch { ... }</div><div>```</div><div><br></div><div>However, though it does solve the stated motivation of removing one level of braces, this form of `guard...else` is hardly an improvement over the status quo:</div><div><br></div><div>```</div><div>let result: Result?</div><div>do { result = try doSomething() } catch { ... }</div><div>```</div><div><br></div></div></div></div>