<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 Dec 7, 2015, at 9:29 PM, Russ Bishop &lt;<a href="mailto:xenadu@gmail.com" class="">xenadu@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">As a library author all this does is promote wrapping errors with useless wrappers. If I touch the filesystem, I am subject to any number of filesystem errors. If I touch the network I am subject to any number of network errors. What is gained by wrapping those? If the OS is updated and the system API throws a new type of error does that mean my library is broken? If not, then the supposed contract is a lie. If my library calls another library, I’ve multiplied the boilerplate to handle that error (now the user needs to catch OtherLibraryErrorType and MyLibraryErrorType where e.innerError is OtherLibraryErrorType). Even if you solved the fragile interface problem there’s still pressure to perform the wrapping (and pressure on library authors not to introduce new error types) because I upgraded the library and now all my catch clauses are incomplete, potentially causing massive breakage due to a minor change in some core library function that ripples outward.</div><br class="Apple-interchange-newline"></div></blockquote></div><br class=""><div class="">Ok, let’s take an example of what you’re describing; I’ll argue that I believe that what you are doing is leaking implementation details that should not be shared. I believe this to be the general case when you simply wrap errors to propagate them up the call stack.&nbsp;</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">func nameOfTheDayOfTheWeek() -&gt; String { /*&nbsp;… */ }</font></div><div class=""><br class=""></div><div class="">Now, let’s say you need to touch the filesystem to implement this because you have a list of days in a text file.</div><div class=""><br class=""></div><div class="">There are several options here:</div><div class=""><br class=""></div><div class=""><ol class="MailOutline"><li class="">Mark the func as <i class="">throws</i>&nbsp;so the IO errors can propagate out.</li><li class="">Mark the func as <i class="">throws</i>&nbsp;so you can “wrap” the error.</li><li class="">Mark the func as <i class="">throws</i>&nbsp;so you can return specific errors for your library.</li><li class="">Return an optional value to signify the error.</li><li class="">Assume the function always works because an invariant you state and convert the error to a “universal error” (as described in this doc:&nbsp;<a href="https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst" class="">https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst</a>)</li></ol><div class=""><br class=""></div></div><div class="">The fact that the function is using IO is an implementation detail, and because of that, it’s my opinion that #1 and #2 are wrong as you’re just propagating the inner implementation details that are subject to change. Option #3 here really seems like overkill for the function as there are only two results: get the name or don’t get the name.</div><div class=""><br class=""></div><div class="">So, this leaves us with #4 and #5.</div><div class=""><br class=""></div><div class="">Of all of the options I listed above, I think all of them have value except #2. However, I would limit the contexts of each of the types of errors because they all have something explicit to say about the contract they are creating.&nbsp;</div><div class=""><br class=""></div><div class="">If you intend for your users of your library to simply be catching you error, logging it, and moving on, what’s the point of using the <i class="">throws</i>&nbsp;construct in the first place? It would seem that you would be much better of simplifying your API and simply use the optional construct (this is the “Simple Domain Errors” construct).</div><div class=""><br class=""></div><div class="">The question really comes down to the “specificity” section; the primary concern here is #2 from the list above - simply wrapping the errors. I think the danger of throwing this out citing Java as the example, is problematic. Java made many mistakes with how it handled exceptions, and Swift takes a different approach to what errors mean.</div><div class=""><br class=""></div><div class="">What I’m asking for in the proposal is the ability for library authors to chose to make a strong contract or a weak contract about the type of errors it can throw. Also, the other vital thing to note here is this: if I’m returning an enum that implements <i class="">ErrorType</i>, I’ve explicitly stated that these are the sum of the errors that I want to handle. Further, it <i class="">only</i>&nbsp;impacts the places in my code where I’ve explicitly <i class="">chosen</i>&nbsp;to handle the different cases of the error differently. If I were to instead specify a protocol or another type, the thing I’m getting out of that is the ability to use the APIs for those types without casting (that is also the exhaustive case, but suffers from none of the breaking change concerns you had above).</div><div class=""><br class=""></div><div class="">It’s up to the library author to determine if their error types are a set of potential issues or a type that simply holds some information so that new error types can be added later.&nbsp;</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">&nbsp;If the OS is updated and the system API throws a new type of error does that mean my library is broken?</div></blockquote><br class=""></div><div class="">Yes (if that error was defined as an enum), just like your libraries are broken if a library you use adds a new enum case; that’s a breaking change. You have the same problem today with this code:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">func f() -&gt; MyEnum { /*&nbsp;… */ }</font></div></div><div class=""><font face="Menlo" class="">let r = f()</font></div><div class=""><font face="Menlo" class="">switch r {</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; case .First: /* do something */</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; case .Last: /* do something */</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><br class=""></div><div class="">Do you also recommend <i class="">always</i>&nbsp;having a default case when working with enums throughout your code? This is just as fragile.&nbsp;</div><div class=""><br class=""></div><div class="">Also, if the counter-argument is that ErrorType is sufficient for all error handling, then Swift should just make it a struct and let’s be done with it.</div><div class=""><br class=""></div><div class="">-David</div></body></html>