[swift-evolution] Type-annotated throws

David Waite david at alkaline-solutions.com
Fri Aug 26 12:58:46 CDT 2016


I believe the issue with checked exceptions in Java are multi-fold.

First, there are both checked and unchecked exceptions, which gives developers a way to avoid checked exceptions completely. RuntimeException is unchecked and meant to handle runtime detectable issues like math overflow or arrays indexed out of bounds, which would be too unwieldy for developers to have to catch explicitly - especially when they may “know” that an expression like "1 + 1" will not overflow. In Swift, many of these issues actually result in a fatal error.

RuntimeExceptions are also used extensively to work around cases where the appropriate checked exception is not defined on an interface or superclass. In these cases you cannot expand the list of checked exceptions declared, but you still want to throw on error. In this case, you wrap your desired exception in a RuntimeException, or just throw your hands up in the air and throw a RuntimeException with a string description. With such a large escape hatch from checked exceptions, the verbosity of doing things “the correct way” becomes a much more obvious burden.

Java does not have pattern matching in exceptions, with built-in support only for switching on class type of caught exception. However, many modules outside the very core of the language declare a single module-level exception, e.g. AWTException. This means there is an impedance mismatch - the declaration of exception types does not map well always to the appropriate recovery mechanism from the exception.

Having checked exceptions makes it more likely that interfaces will not be declared throwing, as the interface creator may not know the appropriate types of exceptions to be declared.

An interface expected to return an object might get the object from the network, filesystem,. or a database - resulting in three different families of possible exception types. This is usually worked around by having a module-level exception that is declared as the checked type, which can hold the actual exception which happened. Because the module-level exceptions do not differentiate classifications of issues, and the implementation of the interface does not have the actual kind of exception as part of the interface contract, you are limited in your ability to handle the exception in your code. It becomes commonplace to have a single “that thing you tried to do failed”, with a long stack trace to enable a developer or someone in a supporting role to diagnose which code was involved in the failure.



This gets to the root of the problem - since the focus is on documenting the class types of exceptions rather than categories of error states, the developer doesn’t feel any of the complexity or verbosity helps them make their code more robust. Instead of considering how to represent errors to your own callers for recovery, it becomes common to just declare the same list of checked exceptions and pass them through upstream unhanded - or to wrap them all in a module-level exception type to simplify the interface. The end result is that the exception mechanism is made more heavyweight via the checked mechanism, but still doesn’t enable developers to make their code more robust.

In the end, I believe the thing to emphasize is that developers of an API need to think of how the errors they raise would be handled by potential callers, and to represent *that* in their API. This might result in a specific error enumeration per method, which is O.K. In that case, declaring such a thrown error so that the error cases may be handled exhaustively is probably a good thing. A declaration which either does not allow exhaustive handling of error cases, or which allows someone to forward errors from multiple sources without thinking about their caller’s error needs are probably not productive.

-DW

> On Aug 26, 2016, at 10:01 AM, Nur Ismail via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Hi,
> 
> Sounds like checked exceptions of Java with a similar syntax. With Java you have to specify the exceptions a method can throw. However been lots of debate over the years whether it's a good thing or bad thing, some like it, but I think many more hate it.
> Most other languages don't have it, and possibly for good reason.
> 
> Regards,
> 
> On Fri, Aug 26, 2016 at 5:43 PM, Rod Brown via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> (resent for Swift Evolution)
> 
> I’m a big fan of this idea. Currently “throws” seems like a very limited API - you know it’s throwing out something, but you can only hope to guess what that is or create fallbacks. Definitely a big +1 from me. A fallback for compatibility could be “throws” assumes “throws Any” and can be a warning?
> 
> While I am not deeply familiar with the implications, I do like think your line of reasoning has merit, and think this makes sense for Phase 1 of Swift 4. 
> 
> - Rod
> 
> 
>> On 27 Aug 2016, at 1:39 AM, Félix Cloutier via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> Hi all,
>> 
>> Currently, a function that throws is assumed to throw anything. There was a proposal draft last December to restrict that. The general idea was that you'd write, for instance:
>> 
>>> enum Foo: ErrorProtocol {
>>>     case bar
>>>     case baz
>>> }
>>> 
>>> func frob() throws Foo {
>>>     throw Foo.bar // throw .bar?
>>> }
>> 
>> If you `catch Foo` (or every case of Foo), now that the compiler can verify that your catch is exhaustive, you no longer have to have a catch-all block at the end of the sequence.
>> 
>> This impacts the metadata format and has implications on resilience, which leads me to believe that the discussion could qualify for the phase 1 of Swift 4. If this is the case, I'd be interested in pulling out the old discussions and seeing where we left that at.
>> 
>> Félix
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160826/12a04ee8/attachment.html>


More information about the swift-evolution mailing list