<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 17 Feb 2017, at 19:45, Anton Zhilin via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="markdown-here-wrapper" style=""><p style="margin:0px 0px 1.2em!important" class="">Now this is on-topic, I guess.<br class="">Last time we stopped at John McCall’s syntax:</p>
<pre style="font-family:Consolas,Inconsolata,Courier,monospace;line-height:1.2em;margin:1.2em 0px" class=""><code style="font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;background-color:rgb(248,248,248);white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important" class="">extension MyError: Error { ... }

func foo() throws(MyError) -&gt; MyResult<span style="font-size:0.85em" class="">
</span></code></pre><p style="margin:0px 0px 1.2em!important" class="">It’s conservative and prevents visual ambiguity with extra parentheses.</p><p style="margin:0px 0px 1.2em!important" class="">If we (somewhat) agree on this, then submitting a proposal will be trivial.</p>
<div title="MDH:Tm93IHRoaXMgaXMgb24tdG9waWMsIEkgZ3Vlc3MuPGRpdj5MYXN0IHRpbWUgd2Ugc3RvcHBlZCBh
dCBKb2huIE1jQ2FsbCdzIHN5bnRheDo8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PmBgYDwvZGl2
PjxkaXY+ZXh0ZW5zaW9uIE15RXJyb3I6IEVycm9yIHsgLi4uIH08L2Rpdj48ZGl2Pjxicj48L2Rp
dj48ZGl2PmZ1bmMgZm9vKCkgdGhyb3dzKE15RXJyb3IpIC0mZ3Q7IE15UmVzdWx0PC9kaXY+PGRp
dj5gYGA8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2Pkl0J3MgY29uc2VydmF0aXZlIGFuZCBwcmV2
ZW50cyB2aXN1YWwgYW1iaWd1aXR5IHdpdGggZXh0cmEgcGFyZW50aGVzZXMuPGJyPjwvZGl2Pjxk
aXY+PGJyPjwvZGl2PjxkaXY+SWYgd2UgKHNvbWV3aGF0KSBhZ3JlZSBvbiB0aGlzLCB0aGVuIHN1
Ym1pdHRpbmcgYSBwcm9wb3NhbCB3aWxsIGJlIHRyaXZpYWwuPC9kaXY+" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0" class="">​</div></div></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""><div class=""><br class=""></div><div class="">So, I’m not sure about what was decided last time, but my issues with this are:</div><div class=""><br class=""></div><div class="">- The thrown error type will become part of the ABI of the function. If you change the type of Error that is thrown, callers may not catch it. At the same time, if we make enums resilient by default and only allow specifying a single entire type, you will basically need one Error enum per function and it will need to be @fixed if you actually want to remove the catch-all block. Otherwise:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">// Let’s say this isn’t @fixed...</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">enum CanFailError {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; errorOne</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; errorTwo</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">func canFail() throws(CanFailError) { /* … */ }</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">do { try canFail() }</font></div><div class=""><font face="Courier" class="">catch&nbsp;</font><span style="font-family: Courier;" class="">CanFailError</span><font face="Courier" class="">&nbsp;{</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; switch error {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; case .errorOne: /* handle error one */</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; case .errorTwo: /* handle error two */</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; default: &nbsp; &nbsp; &nbsp; &nbsp;/* handle possible new errors in later versions of the library */</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; }</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><div class=""><font face="Courier" class="">do { try canFail() }</font></div><div class=""><font face="Courier" class="">catch .errorOne { /* handle error one */ }</font></div><div class=""><font face="Courier" class="">catch .errorTwo { /* handle error two */ &nbsp;}</font></div><div class=""><font face="Courier" class="">catch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { /* handle possible new errors in later versions of the library */ }</font></div><div class=""><br class=""></div></div></blockquote>- I usually have _semantic_ namespaces for Errors, rather than single types per implementation pattern. If we are adding strong annotations about which errors can be thrown, I’d quite like to incorporate that pattern. For example:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">extension File {</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">@fixed&nbsp;</font><span style="font-family: Courier;" class="">enum OpeningError {&nbsp;</span></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">case .invalidPath</span><br class=""><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">case .accessDenied &nbsp;// e.g. asking for write permissions for read-only file</span><br class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class="">@fixed enum ReadError {</font></div></blockquote><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">case .invalidOffset // past EOF</span><br class=""><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">case .deviceError &nbsp; // probably worth aborting the entire operation the read is part of</span><br class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">// - throws:</font></div><div class=""><font face="Courier" class="">// &nbsp; &nbsp; - .OpeningError if the file can’t be opened</font></div><div class=""><font face="Courier" class="">// &nbsp; &nbsp; - .ReadError if the read operation fails</font></div><div class=""><font face="Courier" class="">func read(from offset: Int, into buffer: UnsafeBufferPointer&lt;UInt8&gt;) throws(OpeningError, ReadError) { /* … */ }</font></div></blockquote><font face="Courier" class="">}</font></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class=""></blockquote>- I wonder if we could try something more ambitious. Since the list of thrown errors is resilience-breaking for the function, it is only beneficial for versioned and @inlineable functions. They should not be able to add new errors (they can remove them though, since errors are intended to be switched over). I wonder if we couldn’t introduce a small pattern grammar for our structured comments (isolated from the rest of the language) - it would be optional, but if you do list your errors, the compiler would validate that you do it exhaustively. Some patterns I would like are:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">// - throws: - MyError.{errorOne, errorThree, errorFive}: Something bad &nbsp; &nbsp; &nbsp;|| considered exhaustive</font></div><div class=""><font face="Courier" class="">@inlineable public func canFail() throws {}</font></div><div class=""><br class=""></div><div class=""><font face="Courier" class="">// - throws: -&nbsp;OpeningError: Computer says nooooo... &nbsp; &nbsp; || considered exhaustive if OpeningError is versioned or @fixed</font></div><div class=""><div class=""><font face="Courier" class="">// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - * &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; || other errors, requires “catch-all” by external callers</font></div></div><div class=""><div class=""><font face="Courier" class="">@inlineable public func canFail2() throws {}</font></div></div><div class=""><font face="Courier" class=""><br class=""></font></div></blockquote><div class=""><div class="">If we want to get really clever, we can have the compiler automatically generate those error-lists for internal functions, so you would automatically get exhaustive error-handling within your own module.<br class=""><div class=""><br class=""></div></div></div><div class="">- Karl</div></body></html>