[swift-evolution] Proposal: Allow Type Annotations on Throws

Félix Cloutier felixcca at yahoo.ca
Fri Dec 18 09:03:06 CST 2015


The biggest problem I have with error handling is that most schemes aren't predictable. I like that Swift's model forces you to reduce the possible errors to a single type, most easily an enum type, because this promotes predictability: your function can fail for no more or no less than what the enum has. This goes hand in hand with forcing try on functions that throw, so that you always know what could go wrong and what has gone wrong.

What I invariably hate about the common exception model and the common error code model is that the error conditions are either theoretically or practically infinite. It makes it hard to determine which errors you can actually trigger, which in turns makes it hard to decide which cases should be handled and which cases should be forwarded, which perpetuates that it's hard to determine which errors you can trigger.

Integral error codes are limited, but the limit is far above what human beings can model and consider, and each integral value can be overloaded. Microsoft's HRESULT and Apple's OSStatus are two examples of large and overloaded status codes (see osstatus.com for how bad this can get). Luckily, this model is discouraged with Swift.

Polymorphic exceptions, on their end, have two major shortfalls: they allow an infinite class of errors to be raised at any point where the call graph isn't entirely static (since developers can subclass the error class), and they encourage errors to be classified by kind instead of by cause.

In my opinion, kind-based exception hierarchies are the original sin of exception handling. For a spectacular failure of exception design, look no further than Java's IOException hierarchy. A method that catches an IOException may be dealing with a ClosedChannelException, a MalformedURLException, a UserPrincipalNotFoundException, an UnsupportedEncodingException, or any other of the 31 direct known subclasses (or a subclass of any of these), or any other user subclass. These are all things that can happen during some I/O, but it makes IOException as a catchable type entirely meaningless.

Unfortunately, it's extremely tempting to categorize exceptions by kind, because object-oriented programming is all about categorizing things by kind. This was just one of the platoon of exception hierarchies that fell down the proverbial slippery slope.

For this reason, I don't like to encourage throwing polymorphic types, and I think that it's a misconception to pretend that having a single type in the throws annotation ensures that the function throws a single type. In my opinion, the fact that it's currently possible but awkward to use polymorphic types as errors is exactly as much support as the feature should receive.

> Le 18 déc. 2015 à 08:53:44, Matthew Johnson via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> David,
> 
> Thank you for taking the time to continue working on a proposal for typed throws.  I agree that this feature is very desirable and appreciate the work you’re doing to bring forward a proposal.  I think it’s a great start but also has some room for improvement.
> 
> First, I think it could be strengthened by incorporating some learning from Rust.  My impression is that the Rust community is very happy with typed error handling.  Adding some detail about their experience would provide a counter-example to those who are concerned about the experience in Java and C++.
> 
> I agree that error types are an important part of an API contract.  One of the big hurdles to doing this well is the need to catch errors when all that needs to be done is to wrap and rethrow them.  Ideally should not need to do this just to perform a simple type translation to map the underlying error into the type we wish to expose as part of a stable API contract.  You might want to take a look at the From mechanism Rust uses to facilitate this.  IMO a proposal for typed error handling should address this issue in some way (even if the author determines this mechanism is not necessary or a good design cannot be identified).
> 
> I would also like to see much more detail on why you think allowing a function to throw multiple error types is problematic.  My impression is that you have concerns from a usability point of view.  I am on the fence here to some degree, but definitely leaning in the direction that allowing a function to throw multiple error types is better.  
> 
> The primary reason I lean this way is that it enables more re-use of standard error types.  Custom error types for an API often make sense, but not always.  I am concerned about the need to create them just because our API contract might reasonably include two or three of the standard error types.  Adding new types when they are not necessary introduces complexity and cognitive overhead.  It also complicates catching of errors if the new custom type is a two or three case enum that just embeds the underlying error.  
> 
> These problems will lead many people to just revert to an untyped throws clause.  Objections to typed errors along these lines are common and legitimate.  They will arise during review.  It is best if you address them in the proposal now in order to focus a review on your solutions.  My personal opinion is that allowing multiple error types and including a mechanism to perform automatic wrapping when appropriate would go a long way towards solving them.
> 
> Implementation challenges related to multi-typed errors have been discussed on the list quite a bit already.  They would obviously need to be addressed if we go in that direction.  I don’t want to downplay those.  But I do think we need to try to identify the most usable solution for typed errors that we can first and then focus on implementation details.  If the design needs to be modified to accommodate implementation at least we will have a better idea of what we are giving up.
> 
> I am willing to be convinced that a single error type is better than multiple error types but the current proposal does not provide a compelling argument in that direction.  It just says “Java checked exceptions”.  I know these have been pretty much universally considered a serious design mistake.  My impression is that there are quite a few reasons for that.  I don’t have any direct experience with Java and am not familiar with the details.  If you could elaborate on specifically why you believe allowing multiple error types was a significant contributor to the problem in a manner that indicates that they will be a problem in any language that includes them I would appreciate that.  Links would be sufficient if they are focused on answering this particular question.  
> 
> I’m looking forward to your feedback on these thoughts.
> 
> Thanks,
> Matthew
> 
> 
>> On Dec 18, 2015, at 1:29 AM, David Owens II via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> This a significantly updated proposal for typed annotations on the `throws` construct. The previous was closed due to not be complete; I believe I’ve addressed all of those concerns.
>> 
>> https://github.com/owensd/swift-evolution/blob/master/proposals/allow-type-annotations-on-throw.md <https://github.com/owensd/swift-evolution/blob/master/proposals/allow-type-annotations-on-throw.md>
>> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151218/8180bf75/attachment.html>


More information about the swift-evolution mailing list