[swift-evolution] Move placement of 'throws' statement

Karl razielim at gmail.com
Tue Dec 27 14:44:41 CST 2016


> On 27 Dec 2016, at 13:21, Haravikk <swift-evolution at haravikk.me> wrote:
> 
> 
>> On 27 Dec 2016, at 10:56, Derrick Ho via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> Daniel Leping, I am unfamiliar with java. Do you have any resources that describe the nightmare in detail?
> 
> 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.
> 
> 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.
> 
> 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:
> 
> 	func myMethod(args:[String:Any]) throws IOError, IllegalArgumentError? { … }
> 
> 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.
> 
> 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.
> 
> In addition to this we might introduce some mechanism for specifying *some* of a method's error types, for example:
> 
> 	func myMethod() throws IOError… { … }
> 
> 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.
> 
> 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).
> 
> 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…
> 
> 
> 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.


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. 

Describe a single error:

/// - throws:
///     - POSIXError.EBADF: the descriptor is invalid

Describe a whole enum-full of error cases:

/// - throws:
///     - POSIXError.EBADF: the descriptor is invalid
///     - ReadError: the read operation failed

Maybe make it an exhaustive list with “throws only”:

/// - throws only:
///     - POSIXError.EBADF: the descriptor is invalid
///     - ReadError: the read operation failed

Or maybe we will consider them all to be exhaustive by default, but allow adding a wildcard item to indicate otherwise:

/// - throws:
///     - POSIXError.EBADF: the descriptor is invalid
///     - ReadError: the read operation failed
///     - *

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:

do {
    try readFile()
}
catch error as POSIXError.EBADF {
    // the descriptor is invalid
    [<code>]
}
catch error as ReadError {
    // the read operation failed
    [<code>]
}

- Karl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161227/d5f4b519/attachment.html>


More information about the swift-evolution mailing list