<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 27 Dec 2016, at 13:21, Haravikk <<a href="mailto:swift-evolution@haravikk.me" class="">swift-evolution@haravikk.me</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 27 Dec 2016, at 10:56, Derrick Ho via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">Daniel Leping, I am unfamiliar with java. Do you have any resources that describe the nightmare in detail?<br class=""></div></blockquote></div><br class=""><div class="">I think the problem really comes down to the inflexibility of it; if you specify X, Y, and Z as throwable types, then all code calling that method must handle those types in some way.</div><div class=""><br class=""></div><div class="">Thing is, I wonder if this would be as much of a problem for Swift? We have the try! and try? variations which make it very easy to ignore/simplify error handling if we don't expect any to occur at all, or it doesn't matter if they do, and we have the same basic means of handling generic unknown (or unhandled) error types, plus throws and rethrows.</div><div class=""><br class=""></div><div class="">Part of the problem is that Java only ever treats the specified types as mandatory (you *must* handle them somehow); I think a more elegant solution could be if we could somehow mark them as optional, for example:</div><div class=""><br class=""></div><div class=""><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func myMethod(args:[String:Any]) throws IOError, IllegalArgumentError? { … }</font></div><div class=""><br class=""></div><div class="">Here myMethod can throw two error types, IOError and IllegalArgumentError, but while the first *must* be handled somehow, the latter is only optional as a well formed args dictionary cannot possibly produce an error, i.e- it's an error you might only want to check if the args dictionary was built dynamically.</div><div class=""><br class=""></div><div class="">Basically in this case not handling an IOError would be an error, while not handling IllegalArgumentError would be a warning (with some way to suppress it). This means that APIs could even add new error types so long as they are optional, though it's not advisable.</div><div class=""><br class=""></div><div class="">In addition to this we might introduce some mechanism for specifying *some* of a method's error types, for example:</div><div class=""><br class=""></div><div class=""><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func myMethod() throws IOError… { … }</font></div><div class=""><br class=""></div><div class="">Here myMethod specifies an explicit IOError that *must* be handled, but also indicates that there are other, optional, types that don't need to be handled explicitly. The idea here is that you specify only the most important types, but can still indicate that there are other possible types (but maybe they're rare, or only occur in very unusual circumstances described in documentation), or you just want to leave the definition open-ended.</div><div class=""><br class=""></div><div class="">So yeah; personally I'm a supporter of being *able* to specify thrown types, but do think it needs to be more flexible in what and how we specify them, to avoid falling into the same pitfalls as Java. I definitely think that being able to specify types that *must* be handled is useful, though we'd need to make clear best practice (i.e- mandatory type handling should be reserved for more serious errors in most cases).</div><div class=""><br class=""></div><div class="">Other things to consider are wether explicit thrown types could be marked as handle immediately (i.e- throwing the error up the chain is a warning), and whether non-explicit throws/rethrows could be automatically computed. For example, if I have a method that has a plain throws, and handles three methods, throwing errors of A, B? and C… respectively, with the first called via try?, then my method's throwable types are B?, C…</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">To conclude; while I like Swift's error handling as-is it's mostly because I tend to use try! and try?, but when it comes to an actual try/catch I do like Java's compiler supported enforcement making sure that I'm aware of which types I'm supposed to do something with.</div></div></div></blockquote></div><br class=""><div class=""><br class=""></div><div class="">This is why I think a comment-based system would be better. You can have long lists which describe every error case in detail and what to do about it, without cluttering the function signature. </div><div class=""><br class=""></div><div class="">Describe a single error:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">/// - throws:</font></div><div class=""><font face="Menlo" class="">/// - POSIXError.EBADF: the descriptor is invalid</font></div></div><div class=""><br class=""></div><div class="">Describe a whole enum-full of error cases:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">/// - throws:</font></div><div class=""><font face="Menlo" class="">/// - POSIXError.EBADF: the descriptor is invalid</font></div></div><div class=""><font face="Menlo" class="">/// - ReadError: the read operation failed</font></div><div class=""><br class=""></div><div class="">Maybe make it an exhaustive list with “throws only”:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">/// - throws only:</font></div><div class=""><div class=""><font face="Menlo" class="">/// - POSIXError.EBADF: the descriptor is invalid</font></div><div class=""><font face="Menlo" class="">/// - ReadError: the read operation failed</font></div></div><div class=""><br class=""></div><div class="">Or maybe we will consider them all to be exhaustive by default, but allow adding a wildcard item to indicate otherwise:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">/// - throws:</font></div><div class=""><div class=""><font face="Menlo" class="">/// - POSIXError.EBADF: the descriptor is invalid</font></div><div class=""><font face="Menlo" class="">/// - ReadError: the read operation failed</font></div></div></div><div class=""><font face="Menlo" class="">/// - *</font></div><div class=""><br class=""></div><div class="">We could also use that documentation for quick-help popups on catch statements. IDE-generated do/catch blocks could include comments to help you fill in the details:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">do {</font></div><div class=""><font face="Menlo" class=""> try readFile()</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">catch error as POSIXError.EBADF {</font></div><div class=""><font face="Menlo" class=""> // the descriptor is invalid</font></div><div class=""><font face="Menlo" class=""> [<code>]</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">catch error as ReadError {</font></div><div class=""><font face="Menlo" class=""> // the read operation failed</font></div><div class=""><font face="Menlo" class=""> [<code>]</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><br class=""></div><div class="">- Karl</div></body></html>