# Proposal: Allow Type Annotations on Throws

**URL:** <https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623>\
**Category:** Discussion\
**Created:** [December 18, 2015, 7:29am UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623 "2015-12-18T07:29:50Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![owensd](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owensd/32/8934_2.png) [@owensd](https://forums.swift.org/u/owensd)\
**Post date:** [December 18, 2015, 7:29am UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/1 "2015-12-18T07:29:50Z")

</div>

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)

> **···**
>
> —
> 
> Allow Type Annotation on Throws  
> Proposal: SE-NNNN \<applewebdata://9C8E792C-9803-4E70-811E-D5169EDD5F6D\>  
> Author(s): David Owens II \<applewebdata://9C8E792C-9803-4E70-811E-D5169EDD5F6D\>  
> Status: Pending Approval for Review  
> Review manager: TBD  
> Introduction  
> The error handling system within Swift today creates an implicitly loose contract on the API. While this can be desirable in some cases, it’s certainly not desired in all cases. This proposal looks at modifying how the error handling mechanism works today by adding the ability to provide a strong API contract.
> 
> Error Handling State of the Union  
> This document will use the terminology and the premises defined in the Error Handling Rationale \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document.
> 
> To very briefly summarize, there are four basic classification of errors:
> 
> Simple Domain Errors  
> Recoverable Errors  
> Universal Errors  
> Logic Failures  
> Each of these types of errors are handled differently at the call sites. Today, only the first two are directly handled by Swift error handling mechanism. The second two are uncatchable in Swift (such as fatalError(), ObjC exceptions, and force-unwrapping of null optionals).
> 
> Simple Domain Errors
> 
> As stated in Error Handling Rationale \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document, the “Swift way” to handle such errors is to return an Optional\<T\>.
> 
> func parseInt(value: String) -\> Int? {}  
> The simple fact of the result being Optional.None signifies that the string could not be parsed and converted into an Int. No other information is necessary or warranted.
> 
> Recoverable Errors
> 
> In this context, these are errors that need to provide additional information to the caller. The caller can then decide a course of action that needs to be taken. This could be any number of things, including, but not limited to, logging error information, attempting a retry, or potentially invoking a different code path. All of these errors implement the ErrorType protocol.
> 
> func openFile(filename: String) throws {}  
> The throws keyword annotates that the function can return additional error information. The caller must also explicitly make use of this when invoking the function.
> 
> do {  
> &nbsp;&nbsp;try openFile("path/to/somewhere")  
> }  
> catch {}  
> Errors are able to propagate if called within another context that can throw, thus alleviating the annoying “catch and rethrow” behavior:
> 
> func parent() throws {  
> &nbsp;&nbsp;try openFile("path/to/somwhere")  
> }  
> Lastly, functions can be marked to selectively throw errors if they take a function parameter that throws with the rethrows keyword. The really interesting part is that it’s only necessary to use try when calling the function with a throwing closure.
> 
> func openFile(filename: String) throws {}  
> func say(message: String) {}
> 
> func sample(fn: (\_: String) throws -\> ()) rethrows {  
> &nbsp;&nbsp;&nbsp;&nbsp;try fn("hi")  
> }
> 
> try sample(openFile)  
> sample(say)  
> Converting Recoverable Errors to Domain Errors
> 
> Swift also has the try? construct. The notable thing about this construct is that it allows the caller to turn a “Recoverable Error” into a “Simple Domain Error”.
> 
> if let result = try? openFile("") {}  
> ErrorType Implementors
> 
> Errors are implemented using the ErrorType protocol. Since it is a protocol, new error types can be a class, a struct, or an enum. A type qualified throws clause would allow code authors to change the way that the catch-clauses need to be structured.
> 
> Enum Based ErrorType
> 
> When enums are used as the throwing mechanism, a generic catch-clause is still required as the compiler doesn’t have enough information. This leads to ambiguous code paths.
> 
> enum Errors: ErrorType {  
> &nbsp;&nbsp;&nbsp;&nbsp;case OffBy1  
> &nbsp;&nbsp;&nbsp;&nbsp;case MutatedValue  
> }
> 
> func f() throws { throw Errors.OffBy1 }
> 
> do {  
> &nbsp;&nbsp;&nbsp;&nbsp;try f()  
> }  
> catch Errors.OffBy1 { print("increment by 1") }  
> catch Errors.MutatedValue { fatalError("data corrupted") }  
> The above code requires a catch {} clause, but it’s ambiguous what that case should do. There is no right way to handle this error. If the error is ignored, we’re now in the land of “Logic Errors”; the code path should never be hit. If we use a fatalError() construct, then we are now in the land of converting a potential compiler error into a “Universal Error”.
> 
> Both of these are undesirable.
> 
> Struct and Class Based ErrorType
> 
> In the current design, errors that are thrown require a catch-all all the time. In the proposed design, which will be explained further, a catch-all would not be required if there was a case-clause that matched the base type.
> 
> class ErrorOne: ErrorType {}  
> func g() throws { throw ErrorOne() }
> 
> do {  
> &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> }  
> catch is ErrorOne { print("ErrorOne") }  
> The advantage in these cases are different, these cases do not allow pattern matching over the error type members (as you can in a switch-statement, for example).
> 
> The workaround for this functionality is this:
> 
> class ErrorOne: ErrorType {  
> &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> }
> 
> do {  
> &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> }  
> catch {  
> &nbsp;&nbsp;&nbsp;&nbsp;if let e = error as? ErrorOne {  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch e {  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 0: print("0")  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 1: print("1")  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: print("nothing")  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
> &nbsp;&nbsp;&nbsp;&nbsp;}  
> }  
> This proposal would turn the above into:
> 
> class ErrorOne: ErrorType {  
> &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> }
> 
> do {  
> &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> }  
> catch \_ where error.value == 0 { print("0") }  
> catch \_ where error.value == 1 { print("1") }  
> catch { print("nothing") }  
> }  
> No gymnastics to go through, just straight-forward pattern-matching like you’d expect.
> 
> NOTE: This requires the promotion of the error constant to be allowed through the entirety of the catch-clauses.
> 
> Overriding
> 
> In the context of types, it’s completely possible to override functions with the throws annotations. The rules simply follow the rules today: covariance on the return type is allowed, contravariance is not.
> 
> Generics
> 
> When looking at generics, I cannot come up with a reason why they shouldn’t just work as normal:
> 
> func gen\<SomeError: ErrorType\>() throws SomeError {}  
> The only constraint would be that the specified error type must adhere to the ErrorType protocol. However, this is no different than today:
> 
> func f\<T\>(a: T) throws { throw a }  
> This results in the compiler error:
> 
> Thrown expression type ’T’ does not conform to ‘ErrorType’  
> This seems like it should “just work”.
> 
> Design Change Proposal  
> The design change is simple and straight-forward: allow for the annotation of the type of error that is being returned as an optional restriction. The default value would still be ErrorType.
> 
> func specific() throws MyError {}  
> func nonspecific() throws {}  
> There is a secondary result of this proposal: the error constant should be promoted to be allowed for use through-out all of the catch-clauses.
> 
> Impact on Existing Code
> 
> This is a non-breaking change. All existing constructs work today without change. That said, there are a few places where this change will have an impact on future usage.
> 
> Function Declarations
> 
> When a function has a throws clause that is attributed with a type, then that type becomes part of the function signature. This means that these two functions are not considered to be of the same type:
> 
> func one() throws {}  
> func two() throws NumberError {}  
> The function signatures are covariant though, so either one or two can be assigned to f below:
> 
> let f: () throws -\> ()  
> This is completely fine as NumberError still implements the ErrorType protocol.
> 
> However, in this case:
> 
> let g: () throws NumberError -\> ()  
> It would not be valid to assign one to g as the type signature is more specific.
> 
> throws and rethrows
> 
> Functions currently have the ability to be marked as rethrows. This basically says that if a closure parameter can throw, then the function will throw too.
> 
> func whatever(fn: () throws -\> ()) rethrows {}  
> The whatever function is up for anything that fn is up for. Keeping in line with this mentality, the rethrows would exhibit the same behavior: typed annotations simply apply if present and do not if they are missing.
> 
> func specific(fn: () throws HappyError -\> ()) rethrows {}  
> This all works as expected:
> 
> func f() throws HappyError {}  
> func g() {}
> 
> try specific(f)  
> specific(g)  
> This works for the same covariant reason as the non-qualified throws implementation works: a non-throwing function is always able to be passed in for a throwing function.
> 
> The do-catch statement
> 
> There are two rule changes here, but again, it’s non-breaking.
> 
> The first rule change is to promote the error constant that would normally only be allowed in the catch-all clause (no patterns) to be available throughout each of the catch clauses. This allows for the error information to be used in pattern matching, which is especially valuable in the non-enum case.
> 
> The second change is to allow the error constant to take on a specific type when all of the throwing functions throw the same specified type. When this is the case, two things become possible:
> 
> In the enum-type implementation of ErrorType, the catch-clauses can now be exhaustive.  
> In the all of the cases, the API of the specific ErrorType becomes available in the catch-clause without casting the error constant. This greatly simplifies the pattern-matching process.  
> In the case that there are heterogenous ErrorType implementations being returned, the errorconstant simply has the type of ErrorType.
> 
> The try call sites
> 
> There is no change for the try, try?, or try! uses. The only clarification I’ll add is that try?is still the appropriate way to promote an error from a “Recoverable Error” to a “Simple Domain Error”.
> 
> Alternate Proposals  
> There is another common error handling mechanism used in the community today: Either\<L, R\>. There are various implementations, but they all basically boil down to an enum that captures the value or the error information.
> 
> I actually consider my proposal syntactic sugar over this concept. If and when Swift supports covariant generics, there is not a significant reason I can see why the underlying implementation could not just be that.
> 
> The advantage is that the proposed (and existing) syntax of throws greatly increases the readability and understanding that this function actually possesses the ability to throw errors and they should be handled.
> 
> The other advantage of this syntax is that it doesn’t require a new construct to force the usage of the return type.
> 
> Further, if functions where to ever gain the ability to be marked as async, this could now be handled naturally within the compiler as the return type could a promise-like implementation for those.
> 
> Criticisms  
> From the earlier threads on the swift-evolution mailing list, there are a few primary points of contention about this proposal.
> 
> Aren’t we just creating Java checked-exceptions, which we all know are terrible?
> 
> No. The primary reason is that a function can only return a single error-type. The other major reason is that the error philosophy is very different in Swift than in Java.
> 
> Aren’t we creating fragile APIs that can cause breaking changes?
> 
> Potentially, yes. This depends on how the ABI is handled in Swift 3 for enums. The same problem exists today, although at a lesser extent, for any API that returns an enum today.
> 
> Chris Lattner mentioned this on the thread:
> 
> The resilience model addresses how the public API from a module can evolve without breaking clients (either at the source level or ABI level). Notably, we want the ability to be able to add enum cases to something by default, but also to allow API authors to opt into more performance/strictness by saying that a public enum is “fragile” or “closed for evolution”.  
> So if enums have an attribute that allows API authors to denote the fragility enums, then this can be handled via that route.
> 
> Another potential fix is that only internal and private scoped functions are allowed to use the exhaustive-style catch-clauses. For all public APIs, they would still need the catch-all clauses.
> 
> For APIs that return non-enum based ErrorType implementations, then no, this does not contribute to the fragility problem.
> 
> Aren’t we creating the need for wrapper errors?
> 
> This is a philosophical debate. I’ll simply state that I believe that simply re-throwing an error, say some type of IO error, from your API that is not an IO-based API is design flaw: you are exposing implementation details to users. This creates a fragile API surface.
> 
> Also, since the type annotation is opt-in, I feel like this is a really minor argument. If your function is really able to throw errors from various different API calls, then just stick with the default ErrorType.

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [December 18, 2015, 1:53pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/2 "2015-12-18T13:53:44Z")

</div>

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@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)
> > 
> > —
> > 
> > Allow Type Annotation on Throws  
> > Proposal: SE-NNNN \<applewebdata://E64F564F-E0C7-443D-BB19-243FAD102941\>  
> > Author(s): David Owens II \<applewebdata://E64F564F-E0C7-443D-BB19-243FAD102941\>  
> > Status: Pending Approval for Review  
> > Review manager: TBD  
> > Introduction  
> > The error handling system within Swift today creates an implicitly loose contract on the API. While this can be desirable in some cases, it’s certainly not desired in all cases. This proposal looks at modifying how the error handling mechanism works today by adding the ability to provide a strong API contract.
> > 
> > Error Handling State of the Union  
> > This document will use the terminology and the premises defined in the Error Handling Rationale \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document.
> > 
> > To very briefly summarize, there are four basic classification of errors:
> > 
> > Simple Domain Errors  
> > Recoverable Errors  
> > Universal Errors  
> > Logic Failures  
> > Each of these types of errors are handled differently at the call sites. Today, only the first two are directly handled by Swift error handling mechanism. The second two are uncatchable in Swift (such as fatalError(), ObjC exceptions, and force-unwrapping of null optionals).
> > 
> > Simple Domain Errors
> > 
> > As stated in Error Handling Rationale \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document, the “Swift way” to handle such errors is to return an Optional\<T\>.
> > 
> > func parseInt(value: String) -\> Int? {}  
> > The simple fact of the result being Optional.None signifies that the string could not be parsed and converted into an Int. No other information is necessary or warranted.
> > 
> > Recoverable Errors
> > 
> > In this context, these are errors that need to provide additional information to the caller. The caller can then decide a course of action that needs to be taken. This could be any number of things, including, but not limited to, logging error information, attempting a retry, or potentially invoking a different code path. All of these errors implement the ErrorType protocol.
> > 
> > func openFile(filename: String) throws {}  
> > The throws keyword annotates that the function can return additional error information. The caller must also explicitly make use of this when invoking the function.
> > 
> > do {  
> > &nbsp;&nbsp;try openFile("path/to/somewhere")  
> > }  
> > catch {}  
> > Errors are able to propagate if called within another context that can throw, thus alleviating the annoying “catch and rethrow” behavior:
> > 
> > func parent() throws {  
> > &nbsp;&nbsp;try openFile("path/to/somwhere")  
> > }  
> > Lastly, functions can be marked to selectively throw errors if they take a function parameter that throws with the rethrows keyword. The really interesting part is that it’s only necessary to use try when calling the function with a throwing closure.
> > 
> > func openFile(filename: String) throws {}  
> > func say(message: String) {}
> > 
> > func sample(fn: (\_: String) throws -\> ()) rethrows {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try fn("hi")  
> > }
> > 
> > try sample(openFile)  
> > sample(say)  
> > Converting Recoverable Errors to Domain Errors
> > 
> > Swift also has the try? construct. The notable thing about this construct is that it allows the caller to turn a “Recoverable Error” into a “Simple Domain Error”.
> > 
> > if let result = try? openFile("") {}  
> > ErrorType Implementors
> > 
> > Errors are implemented using the ErrorType protocol. Since it is a protocol, new error types can be a class, a struct, or an enum. A type qualified throws clause would allow code authors to change the way that the catch-clauses need to be structured.
> > 
> > Enum Based ErrorType
> > 
> > When enums are used as the throwing mechanism, a generic catch-clause is still required as the compiler doesn’t have enough information. This leads to ambiguous code paths.
> > 
> > enum Errors: ErrorType {  
> > &nbsp;&nbsp;&nbsp;&nbsp;case OffBy1  
> > &nbsp;&nbsp;&nbsp;&nbsp;case MutatedValue  
> > }
> > 
> > func f() throws { throw Errors.OffBy1 }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try f()  
> > }  
> > catch Errors.OffBy1 { print("increment by 1") }  
> > catch Errors.MutatedValue { fatalError("data corrupted") }  
> > The above code requires a catch {} clause, but it’s ambiguous what that case should do. There is no right way to handle this error. If the error is ignored, we’re now in the land of “Logic Errors”; the code path should never be hit. If we use a fatalError() construct, then we are now in the land of converting a potential compiler error into a “Universal Error”.
> > 
> > Both of these are undesirable.
> > 
> > Struct and Class Based ErrorType
> > 
> > In the current design, errors that are thrown require a catch-all all the time. In the proposed design, which will be explained further, a catch-all would not be required if there was a case-clause that matched the base type.
> > 
> > class ErrorOne: ErrorType {}  
> > func g() throws { throw ErrorOne() }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > }  
> > catch is ErrorOne { print("ErrorOne") }  
> > The advantage in these cases are different, these cases do not allow pattern matching over the error type members (as you can in a switch-statement, for example).
> > 
> > The workaround for this functionality is this:
> > 
> > class ErrorOne: ErrorType {  
> > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > }  
> > catch {  
> > &nbsp;&nbsp;&nbsp;&nbsp;if let e = error as? ErrorOne {  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch e {  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 0: print("0")  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 1: print("1")  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: print("nothing")  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
> > &nbsp;&nbsp;&nbsp;&nbsp;}  
> > }  
> > This proposal would turn the above into:
> > 
> > class ErrorOne: ErrorType {  
> > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > }  
> > catch \_ where error.value == 0 { print("0") }  
> > catch \_ where error.value == 1 { print("1") }  
> > catch { print("nothing") }  
> > }  
> > No gymnastics to go through, just straight-forward pattern-matching like you’d expect.
> > 
> > NOTE: This requires the promotion of the error constant to be allowed through the entirety of the catch-clauses.
> > 
> > Overriding
> > 
> > In the context of types, it’s completely possible to override functions with the throws annotations. The rules simply follow the rules today: covariance on the return type is allowed, contravariance is not.
> > 
> > Generics
> > 
> > When looking at generics, I cannot come up with a reason why they shouldn’t just work as normal:
> > 
> > func gen\<SomeError: ErrorType\>() throws SomeError {}  
> > The only constraint would be that the specified error type must adhere to the ErrorType protocol. However, this is no different than today:
> > 
> > func f\<T\>(a: T) throws { throw a }  
> > This results in the compiler error:
> > 
> > Thrown expression type ’T’ does not conform to ‘ErrorType’  
> > This seems like it should “just work”.
> > 
> > Design Change Proposal  
> > The design change is simple and straight-forward: allow for the annotation of the type of error that is being returned as an optional restriction. The default value would still be ErrorType.
> > 
> > func specific() throws MyError {}  
> > func nonspecific() throws {}  
> > There is a secondary result of this proposal: the error constant should be promoted to be allowed for use through-out all of the catch-clauses.
> > 
> > Impact on Existing Code
> > 
> > This is a non-breaking change. All existing constructs work today without change. That said, there are a few places where this change will have an impact on future usage.
> > 
> > Function Declarations
> > 
> > When a function has a throws clause that is attributed with a type, then that type becomes part of the function signature. This means that these two functions are not considered to be of the same type:
> > 
> > func one() throws {}  
> > func two() throws NumberError {}  
> > The function signatures are covariant though, so either one or two can be assigned to f below:
> > 
> > let f: () throws -\> ()  
> > This is completely fine as NumberError still implements the ErrorType protocol.
> > 
> > However, in this case:
> > 
> > let g: () throws NumberError -\> ()  
> > It would not be valid to assign one to g as the type signature is more specific.
> > 
> > throws and rethrows
> > 
> > Functions currently have the ability to be marked as rethrows. This basically says that if a closure parameter can throw, then the function will throw too.
> > 
> > func whatever(fn: () throws -\> ()) rethrows {}  
> > The whatever function is up for anything that fn is up for. Keeping in line with this mentality, the rethrows would exhibit the same behavior: typed annotations simply apply if present and do not if they are missing.
> > 
> > func specific(fn: () throws HappyError -\> ()) rethrows {}  
> > This all works as expected:
> > 
> > func f() throws HappyError {}  
> > func g() {}
> > 
> > try specific(f)  
> > specific(g)  
> > This works for the same covariant reason as the non-qualified throws implementation works: a non-throwing function is always able to be passed in for a throwing function.
> > 
> > The do-catch statement
> > 
> > There are two rule changes here, but again, it’s non-breaking.
> > 
> > The first rule change is to promote the error constant that would normally only be allowed in the catch-all clause (no patterns) to be available throughout each of the catch clauses. This allows for the error information to be used in pattern matching, which is especially valuable in the non-enum case.
> > 
> > The second change is to allow the error constant to take on a specific type when all of the throwing functions throw the same specified type. When this is the case, two things become possible:
> > 
> > In the enum-type implementation of ErrorType, the catch-clauses can now be exhaustive.  
> > In the all of the cases, the API of the specific ErrorType becomes available in the catch-clause without casting the error constant. This greatly simplifies the pattern-matching process.  
> > In the case that there are heterogenous ErrorType implementations being returned, the errorconstant simply has the type of ErrorType.
> > 
> > The try call sites
> > 
> > There is no change for the try, try?, or try! uses. The only clarification I’ll add is that try?is still the appropriate way to promote an error from a “Recoverable Error” to a “Simple Domain Error”.
> > 
> > Alternate Proposals  
> > There is another common error handling mechanism used in the community today: Either\<L, R\>. There are various implementations, but they all basically boil down to an enum that captures the value or the error information.
> > 
> > I actually consider my proposal syntactic sugar over this concept. If and when Swift supports covariant generics, there is not a significant reason I can see why the underlying implementation could not just be that.
> > 
> > The advantage is that the proposed (and existing) syntax of throws greatly increases the readability and understanding that this function actually possesses the ability to throw errors and they should be handled.
> > 
> > The other advantage of this syntax is that it doesn’t require a new construct to force the usage of the return type.
> > 
> > Further, if functions where to ever gain the ability to be marked as async, this could now be handled naturally within the compiler as the return type could a promise-like implementation for those.
> > 
> > Criticisms  
> > From the earlier threads on the swift-evolution mailing list, there are a few primary points of contention about this proposal.
> > 
> > Aren’t we just creating Java checked-exceptions, which we all know are terrible?
> > 
> > No. The primary reason is that a function can only return a single error-type. The other major reason is that the error philosophy is very different in Swift than in Java.
> > 
> > Aren’t we creating fragile APIs that can cause breaking changes?
> > 
> > Potentially, yes. This depends on how the ABI is handled in Swift 3 for enums. The same problem exists today, although at a lesser extent, for any API that returns an enum today.
> > 
> > Chris Lattner mentioned this on the thread:
> > 
> > The resilience model addresses how the public API from a module can evolve without breaking clients (either at the source level or ABI level). Notably, we want the ability to be able to add enum cases to something by default, but also to allow API authors to opt into more performance/strictness by saying that a public enum is “fragile” or “closed for evolution”.  
> > So if enums have an attribute that allows API authors to denote the fragility enums, then this can be handled via that route.
> > 
> > Another potential fix is that only internal and private scoped functions are allowed to use the exhaustive-style catch-clauses. For all public APIs, they would still need the catch-all clauses.
> > 
> > For APIs that return non-enum based ErrorType implementations, then no, this does not contribute to the fragility problem.
> > 
> > Aren’t we creating the need for wrapper errors?
> > 
> > This is a philosophical debate. I’ll simply state that I believe that simply re-throwing an error, say some type of IO error, from your API that is not an IO-based API is design flaw: you are exposing implementation details to users. This creates a fragile API surface.
> > 
> > Also, since the type annotation is opt-in, I feel like this is a really minor argument. If your function is really able to throw errors from various different API calls, then just stick with the default ErrorType.
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![Chris\_Lattner](https://avatars.discourse-cdn.com/v4/letter/c/bc8723/32.png) [@Chris\_Lattner](https://forums.swift.org/u/Chris_Lattner)\
**Post date:** [December 18, 2015, 8:15pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/3 "2015-12-18T20:15:10Z")

</div>

I haven’t had a chance to read this update in detail (but I have skimmed it): with that as a caveat, I am s till +1 on the proposal, and agree that we should stick with 0 or 1 declared thrown types. It should also only happen after resilience features for enums are in place.

-Chris

> **···**
>
> > On Dec 17, 2015, at 11:29 PM, David Owens II via swift-evolution \<swift-evolution@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)

---

<div class="post-metadata">

**Author:** ![owensd](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owensd/32/8934_2.png) [@owensd](https://forums.swift.org/u/owensd)\
**Post date:** [December 18, 2015, 4:50pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/4 "2015-12-18T16:50:41Z")

</div>

> 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’m not involved in the Rust community so I wouldn’t feel comfortable making claims for them.

> 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).

The From() construct seems like a map(T) -\> U problem, but it seems heavily tied into the ability to create sum types. Swift doesn’t have this feature, and that feature is out-of-scope for this proposal. More on this later.

> 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.

Sure. There’s no functionality today to auto-generate a sum type in Swift today, and that is what this request really is. If you want to return multiple return types, then you need to do exactly what Rust does and create a sum type that composes the various types of errors. This exposes the same potential fragile API surface as extending enums do. I did call this part out specifically.

I see this functionality as a general limitation in the language. For example, errors are not the only context where you may want to return a type of A, B, or C. There have been other proposals on how we might do that in Swift. If and when it was solved in the general case for type parameters, I can’t foresee a compelling reason why it wouldn’t work in this context as well.

> 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 guess I should have just specifically called this out in the proposal. It’s not because of “Java checked exceptions”, it’s because nowhere else in the language are types allowed to be essentially annotated in a sum-like fashion. We can’t directly say a function returns an Int or a String. We can’t say a parameter can take an Int or a Double. Similarly, I propose we can’t say a function can return an error A or B.

Thus, the primary reason is about type-system consistency.

Swift already supports a construct to create sum types: associated enums. What it doesn’t allow is the ability to create them in a syntactic shorthand. In this way, my error proposal does the same thing as Rust: multiple return types need to be combined into a single-type - enum.

On to Félix’s comments now!

-David

> **···**
>
> > On Dec 18, 2015, at 5:53 AM, Matthew Johnson \<matthew@anandabits.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Felix\_Cloutier1](https://avatars.discourse-cdn.com/v4/letter/f/e47c2d/32.png) [@Felix\_Cloutier1](https://forums.swift.org/u/Felix_Cloutier1)\
**Post date:** [December 18, 2015, 3:03pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/5 "2015-12-18T15:03:06Z")

</div>

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@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@swift.org \<mailto:swift-evolution@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)

---

<div class="post-metadata">

**Author:** ![dennislysenko](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dennislysenko/32/41738_2.png) [@dennislysenko](https://forums.swift.org/u/dennislysenko)\
**Post date:** [December 18, 2015, 3:25pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/6 "2015-12-18T15:25:14Z")

</div>

Genuinely, David, thank you for taking up the mantle of this problem. To  
me, the lack of type annotations makes the error handling painful and I  
wish the team just hadn't released it until the design was smoothed out  
fully. Those dangling catch-all blocks when I've caught all cases make it  
uselessly verbose and moreover do not fit with the language at all.

As for the multiple vs. single type annotations, I do think that you need a  
concrete example of why this will be different from java to quell the  
concerns of all the people that skim the proposal, don't think about it,  
and exclaim "but everyone hates it in Java!" so I agree on the singular  
type annotations.

Also, your point about being able to mark functions async strongly supports  
single type annotations until we get union types (if ever).

I am glad you addressed covariance/contravariance and the semantics of  
function types when they throw general errors vs. a specific one.

One question, mainly to the compiler team: would it be reasonable to be  
able to use generics covariant over the throws operator? For example, I  
could define a function that takes a function which throws E and returns R,  
and creates a function that takes a callback which takes an argument of  
type Either\<R, E\> instead. This would be an incredibly powerful feature.

> **···**
>
> On Fri, Dec 18, 2015, 8:53 AM Matthew Johnson via swift-evolution \< swift-evolution@swift.org\> wrote:
> 
> > 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@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)
> > 
> > —
> > 
> > Allow Type Annotation on Throws
> > 
> > &nbsp;&nbsp;&nbsp;- Proposal: SE-NNNN  
> > &nbsp;&nbsp;&nbsp;- Author(s): David Owens II  
> > &nbsp;&nbsp;&nbsp;- Status: \*Pending Approval for Review\*  
> > &nbsp;&nbsp;&nbsp;- Review manager: TBD
> > 
> > Introduction
> > 
> > The error handling system within Swift today creates an implicitly loose  
> > contract on the API. While this can be desirable in some cases, it’s  
> > certainly not desired in \*all\* cases. This proposal looks at modifying  
> > how the error handling mechanism works today by adding the ability to  
> > provide a strong API contract.  
> > Error Handling State of the Union
> > 
> > This document will use the terminology and the premises defined in the Error  
> > Handling Rationale  
> > \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt);  
> > document.
> > 
> > To very briefly summarize, there are four basic classification of errors:
> > 
> > &nbsp;&nbsp;&nbsp;1. Simple Domain Errors  
> > &nbsp;&nbsp;&nbsp;2. Recoverable Errors  
> > &nbsp;&nbsp;&nbsp;3. Universal Errors  
> > &nbsp;&nbsp;&nbsp;4. Logic Failures
> > 
> > Each of these types of errors are handled differently at the call sites.  
> > Today, only the first two are directly handled by Swift error handling  
> > mechanism. The second two are uncatchable in Swift (such as fatalError(),  
> > ObjC exceptions, and force-unwrapping of null optionals).  
> > Simple Domain Errors
> > 
> > As stated in Error Handling Rationale  
> > \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document,  
> > the “Swift way” to handle such errors is to return an Optional\<T\>.
> > 
> > func parseInt(value: String) -\> Int? {}
> > 
> > The simple fact of the result being Optional.None signifies that the  
> > string could not be parsed and converted into an Int. No other  
> > information is necessary or warranted.  
> > Recoverable Errors
> > 
> > In this context, these are errors that need to provide additional  
> > information to the caller. The caller can then decide a course of action  
> > that needs to be taken. This could be any number of things, including, but  
> > not limited to, logging error information, attempting a retry, or  
> > potentially invoking a different code path. All of these errors implement  
> > the ErrorType protocol.
> > 
> > func openFile(filename: String) throws {}
> > 
> > The throws keyword annotates that the function can return additional  
> > error information. The caller must also explicitly make use of this when  
> > invoking the function.
> > 
> > do {  
> > &nbsp;&nbsp;try openFile("path/to/somewhere")  
> > }  
> > catch {}
> > 
> > Errors are able to propagate if called within another context that can  
> > throw, thus alleviating the annoying “catch and rethrow” behavior:
> > 
> > func parent() throws {  
> > &nbsp;&nbsp;try openFile("path/to/somwhere")  
> > }
> > 
> > Lastly, functions can be marked to selectively throw errors if they take a  
> > function parameter that throws with the rethrows keyword. The really  
> > interesting part is that it’s only necessary to use try when calling the  
> > function with a throwing closure.
> > 
> > func openFile(filename: String) throws {}  
> > func say(message: String) {}
> > 
> > func sample(fn: (\_: String) throws -\> ()) rethrows {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try fn("hi")  
> > }
> > 
> > try sample(openFile)  
> > sample(say)
> > 
> > Converting Recoverable Errors to Domain Errors
> > 
> > Swift also has the try? construct. The notable thing about this construct  
> > is that it allows the caller to turn a “Recoverable Error” into a “Simple  
> > Domain Error”.
> > 
> > if let result = try? openFile("") {}
> > 
> > ErrorType Implementors
> > 
> > Errors are implemented using the ErrorType protocol. Since it is a  
> > protocol, new error types can be a class, a struct, or an enum. A type  
> > qualified throws clause would allow code authors to change the way that  
> > the catch-clauses need to be structured.  
> > Enum Based ErrorType
> > 
> > When enums are used as the throwing mechanism, a generic catch-clause is  
> > still required as the compiler doesn’t have enough information. This leads  
> > to ambiguous code paths.
> > 
> > enum Errors: ErrorType {  
> > &nbsp;&nbsp;&nbsp;&nbsp;case OffBy1  
> > &nbsp;&nbsp;&nbsp;&nbsp;case MutatedValue  
> > }
> > 
> > func f() throws { throw Errors.OffBy1 }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try f()  
> > }  
> > catch Errors.OffBy1 { print("increment by 1") }  
> > catch Errors.MutatedValue { fatalError("data corrupted") }
> > 
> > The above code requires a catch {} clause, but it’s ambiguous what that  
> > case should do. There is no \*right\* way to handle this error. If the  
> > error is ignored, we’re now in the land of “Logic Errors”; the code path  
> > should never be hit. If we use a fatalError() construct, then we are now  
> > in the land of converting a potential compiler error into a “Universal  
> > Error”.
> > 
> > Both of these are undesirable.  
> > Struct and Class Based ErrorType
> > 
> > In the current design, errors that are thrown require a catch-all all the  
> > time. In the proposed design, which will be explained further, a catch-all  
> > would not be required if there was a case-clause that matched the base type.
> > 
> > class ErrorOne: ErrorType {}  
> > func g() throws { throw ErrorOne() }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > }  
> > catch is ErrorOne { print("ErrorOne") }
> > 
> > The advantage in these cases are different, these cases do not allow  
> > pattern matching over the error type members (as you can in a  
> > switch-statement, for example).
> > 
> > The workaround for this functionality is this:
> > 
> > class ErrorOne: ErrorType {  
> > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > }  
> > catch {  
> > &nbsp;&nbsp;&nbsp;&nbsp;if let e = error as? ErrorOne {  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch e {  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 0: print("0")  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 1: print("1")  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: print("nothing")  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
> > &nbsp;&nbsp;&nbsp;&nbsp;}  
> > }
> > 
> > This proposal would turn the above into:
> > 
> > class ErrorOne: ErrorType {  
> > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > }
> > 
> > do {  
> > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > }  
> > catch \_ where error.value == 0 { print("0") }  
> > catch \_ where error.value == 1 { print("1") }  
> > catch { print("nothing") }  
> > }
> > 
> > No gymnastics to go through, just straight-forward pattern-matching like  
> > you’d expect.
> > 
> > NOTE: This requires the promotion of the error constant to be allowed  
> > through the entirety of the catch-clauses.  
> > Overriding
> > 
> > In the context of types, it’s completely possible to override functions  
> > with the throws annotations. The rules simply follow the rules today:  
> > covariance on the return type is allowed, contravariance is not.  
> > Generics
> > 
> > When looking at generics, I cannot come up with a reason why they  
> > shouldn’t just work as normal:
> > 
> > func gen\<SomeError: ErrorType\>() throws SomeError {}
> > 
> > The only constraint would be that the specified error type must adhere to  
> > the ErrorType protocol. However, this is no different than today:
> > 
> > func f\<T\>(a: T) throws { throw a }
> > 
> > This results in the compiler error:
> > 
> > Thrown expression type ’T’ does not conform to ‘ErrorType’
> > 
> > This seems like it should “just work”.  
> > Design Change Proposal
> > 
> > The design change is simple and straight-forward: allow for the annotation  
> > of the type of error that is being returned as an optional restriction. The  
> > default value would still be ErrorType.
> > 
> > func specific() throws MyError {}  
> > func nonspecific() throws {}
> > 
> > There is a secondary result of this proposal: the error constant should  
> > be promoted to be allowed for use through-out all of the catch-clauses.  
> > Impact on Existing Code
> > 
> > This is a non-breaking change. All existing constructs work today without  
> > change. That said, there are a few places where this change will have an  
> > impact on future usage.  
> > Function Declarations
> > 
> > When a function has a throws clause that is attributed with a type, then  
> > that type becomes part of the function signature. This means that these two  
> > functions are not considered to be of the same type:
> > 
> > func one() throws {}  
> > func two() throws NumberError {}
> > 
> > The function signatures are covariant though, so either one or two can be  
> > assigned to f below:
> > 
> > let f: () throws -\> ()
> > 
> > This is completely fine as NumberError still implements the ErrorType  
> > protocol.
> > 
> > However, in this case:
> > 
> > let g: () throws NumberError -\> ()
> > 
> > It would not be valid to assign one to g as the type signature is more  
> > specific.  
> > throws and rethrows
> > 
> > Functions currently have the ability to be marked as rethrows. This  
> > basically says that if a closure parameter can throw, then the function  
> > will throw too.
> > 
> > func whatever(fn: () throws -\> ()) rethrows {}
> > 
> > The whatever function is up for anything that fn is up for. Keeping in  
> > line with this mentality, the rethrows would exhibit the same behavior:  
> > typed annotations simply apply if present and do not if they are missing.
> > 
> > func specific(fn: () throws HappyError -\> ()) rethrows {}
> > 
> > This all works as expected:
> > 
> > func f() throws HappyError {}  
> > func g() {}
> > 
> > try specific(f)  
> > specific(g)
> > 
> > This works for the same covariant reason as the non-qualified throws implementation  
> > works: a non-throwing function is always able to be passed in for a  
> > throwing function.  
> > The do-catch statement
> > 
> > There are two rule changes here, but again, it’s non-breaking.
> > 
> > The first rule change is to promote the error constant that would  
> > normally only be allowed in the catch-all clause (no patterns) to be  
> > available throughout each of the catch clauses. This allows for the error  
> > information to be used in pattern matching, which is especially valuable in  
> > the non-enum case.
> > 
> > The second change is to allow the error constant to take on a specific  
> > type when \*all\* of the throwing functions throw the same specified type.  
> > When this is the case, two things become possible:
> > 
> > &nbsp;&nbsp;&nbsp;1. In the enum-type implementation of ErrorType, the catch-clauses can  
> > &nbsp;&nbsp;&nbsp;now be exhaustive.  
> > &nbsp;&nbsp;&nbsp;2. In the all of the cases, the API of the specific ErrorType becomes  
> > &nbsp;&nbsp;&nbsp;available in the catch-clause without casting the error constant. This  
> > &nbsp;&nbsp;&nbsp;greatly simplifies the pattern-matching process.
> > 
> > In the case that there are heterogenous ErrorType implementations being  
> > returned, the errorconstant simply has the type of ErrorType.  
> > The try call sites
> > 
> > There is no change for the try, try?, or try! uses. The only  
> > clarification I’ll add is that try?is still the appropriate way to  
> > promote an error from a “Recoverable Error” to a “Simple Domain Error”.  
> > Alternate Proposals
> > 
> > There is another common error handling mechanism used in the community  
> > today: Either\<L, R\>. There are various implementations, but they all  
> > basically boil down to an enum that captures the value or the error  
> > information.
> > 
> > I actually consider my proposal syntactic sugar over this concept. If and  
> > when Swift supports covariant generics, there is not a significant reason I  
> > can see why the underlying implementation could not just be that.
> > 
> > The advantage is that the proposed (and existing) syntax of throws greatly  
> > increases the readability and understanding that this function actually  
> > possesses the ability to throw errors and they should be handled.
> > 
> > The other advantage of this syntax is that it doesn’t require a new  
> > construct to force the usage of the return type.
> > 
> > Further, if functions where to ever gain the ability to be marked as async,  
> > this could now be handled naturally within the compiler as the return type  
> > could a promise-like implementation for those.  
> > Criticisms
> > 
> > From the earlier threads on the swift-evolution mailing list, there are a  
> > few primary points of contention about this proposal.  
> > Aren’t we just creating Java checked-exceptions, which we all know are  
> > terrible?
> > 
> > No. The primary reason is that a function can only return a single  
> > error-type. The other major reason is that the error philosophy is very  
> > different in Swift than in Java.  
> > Aren’t we creating fragile APIs that can cause breaking changes?
> > 
> > Potentially, yes. This depends on how the ABI is handled in Swift 3 for  
> > enums. The same problem exists today, although at a lesser extent, for any  
> > API that returns an enum today.
> > 
> > Chris Lattner mentioned this on the thread:
> > 
> > The resilience model addresses how the public API from a module can evolve  
> > without breaking clients (either at the source level or ABI level).  
> > Notably, we want the ability to be able to add enum cases to something by  
> > default, but also to allow API authors to opt into more  
> > performance/strictness by saying that a public enum is “fragile” or “closed  
> > for evolution”.
> > 
> > So if enums have an attribute that allows API authors to denote the  
> > fragility enums, then this can be handled via that route.
> > 
> > Another potential fix is that \*only\* internal and private scoped  
> > functions are allowed to use the exhaustive-style catch-clauses. For all  
> > public APIs, they would still need the catch-all clauses.
> > 
> > For APIs that return non-enum based ErrorType implementations, then no,  
> > this does not contribute to the fragility problem.  
> > Aren’t we creating the need for wrapper errors?
> > 
> > This is a philosophical debate. I’ll simply state that I believe that  
> > simply re-throwing an error, say some type of IO error, from your API that  
> > is not an IO-based API is design flaw: you are exposing implementation  
> > details to users. This creates a fragile API surface.
> > 
> > Also, since the type annotation is opt-in, I feel like this is a really  
> > minor argument. If your function is really able to throw errors from  
> > various different API calls, then just stick with the default ErrorType.  
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![owensd](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owensd/32/8934_2.png) [@owensd](https://forums.swift.org/u/owensd)\
**Post date:** [December 18, 2015, 4:58pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/7 "2015-12-18T16:58:44Z")

</div>

I don’t follow this. Declaring a type that is an enum or a struct absolutely guarantees that the function only returns a single type. If the type is a class-based error, then sure, there’s not guarantee.

However, the only option today is polymorphic error types.

-David

> **···**
>
> > On Dec 18, 2015, at 7:03 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:
> > 
> > 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.

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [December 18, 2015, 3:21pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/8 "2015-12-18T15:21:12Z")

</div>

> 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 \<[http://osstatus.com/&gt](http://osstatus.com/&gt); for how bad this can get). Luckily, this model is discouraged with Swift.

+1 to these comments. A finite list of non-polymorphic error types (ideally enums to explicitly declare the cases) has the same advantages of discoverability. It also has the potential advantage that it is would be easier to re-use error types. If this is done carefully it could facilitate improved re-use of error handling code. The potential downside is that it could encourage less thoughtful API contracts where people just add any error type they might trigger to the list. An error translation mechanism similar to From in Rust is probably necessary to mitigate this.

> 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.

Agree. This sounds awful.

> 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.

I agree with most of what you’re stating here. Except that the only type information currently available for throwing functions is that they throw `ErrorType`. It doesn’t get more polymorphic than that!

> **···**
>
> > On Dec 18, 2015, at 9:03 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:
> 
> > > Le 18 déc. 2015 à 08:53:44, Matthew Johnson via swift-evolution \<swift-evolution@swift.org \<mailto:swift-evolution@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@swift.org \<mailto:swift-evolution@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)

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [December 18, 2015, 3:40pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/9 "2015-12-18T15:40:13Z")

</div>

> Genuinely, David, thank you for taking up the mantle of this problem. To me, the lack of type annotations makes the error handling painful and I wish the team just hadn't released it until the design was smoothed out fully. Those dangling catch-all blocks when I've caught all cases make it uselessly verbose and moreover do not fit with the language at all.
> 
> As for the multiple vs. single type annotations, I do think that you need a concrete example of why this will be different from java to quell the concerns of all the people that skim the proposal, don't think about it, and exclaim "but everyone hates it in Java!" so I agree on the singular type annotations.

I definitely agree that we need to address the Java problem. That said, I don’t think avoiding knee-jerk objection from people who don’t read and consider a proposal carefully is a good way to approach design. There may be good reasons to choose singular type annotations but this is not one of them.

I believe Félix raised good points about polymorphism and complex hierarchy causing problems in Java. That sounds like it is the source of at least a significant part of the problems with Java’s checked exception model.

> **···**
>
> > On Dec 18, 2015, at 9:25 AM, Dennis Lysenko \<dennis.s.lysenko@gmail.com\> wrote:  
> > Also, your point about being able to mark functions async strongly supports single type annotations until we get union types (if ever).
> > 
> > I am glad you addressed covariance/contravariance and the semantics of function types when they throw general errors vs. a specific one.
> > 
> > One question, mainly to the compiler team: would it be reasonable to be able to use generics covariant over the throws operator? For example, I could define a function that takes a function which throws E and returns R, and creates a function that takes a callback which takes an argument of type Either\<R, E\> instead. This would be an incredibly powerful feature.
> > 
> > On Fri, Dec 18, 2015, 8:53 AM Matthew Johnson via swift-evolution \<swift-evolution@swift.org \<mailto:swift-evolution@swift.org\>\> wrote:  
> > 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@swift.org \<mailto:swift-evolution@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)
> > > 
> > > —
> > > 
> > > Allow Type Annotation on Throws  
> > > Proposal: SE-NNNN \<\>  
> > > Author(s): David Owens II \<\>  
> > > Status: Pending Approval for Review  
> > > Review manager: TBD  
> > > Introduction  
> > > The error handling system within Swift today creates an implicitly loose contract on the API. While this can be desirable in some cases, it’s certainly not desired in all cases. This proposal looks at modifying how the error handling mechanism works today by adding the ability to provide a strong API contract.
> > > 
> > > Error Handling State of the Union  
> > > This document will use the terminology and the premises defined in the Error Handling Rationale \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document.
> > > 
> > > To very briefly summarize, there are four basic classification of errors:
> > > 
> > > Simple Domain Errors  
> > > Recoverable Errors  
> > > Universal Errors  
> > > Logic Failures  
> > > Each of these types of errors are handled differently at the call sites. Today, only the first two are directly handled by Swift error handling mechanism. The second two are uncatchable in Swift (such as fatalError(), ObjC exceptions, and force-unwrapping of null optionals).
> > > 
> > > Simple Domain Errors
> > > 
> > > As stated in Error Handling Rationale \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document, the “Swift way” to handle such errors is to return an Optional\<T\>.
> > > 
> > > func parseInt(value: String) -\> Int? {}  
> > > The simple fact of the result being Optional.None signifies that the string could not be parsed and converted into an Int. No other information is necessary or warranted.
> > > 
> > > Recoverable Errors
> > > 
> > > In this context, these are errors that need to provide additional information to the caller. The caller can then decide a course of action that needs to be taken. This could be any number of things, including, but not limited to, logging error information, attempting a retry, or potentially invoking a different code path. All of these errors implement the ErrorType protocol.
> > > 
> > > func openFile(filename: String) throws {}  
> > > The throws keyword annotates that the function can return additional error information. The caller must also explicitly make use of this when invoking the function.
> > > 
> > > do {  
> > > &nbsp;&nbsp;try openFile("path/to/somewhere")  
> > > }  
> > > catch {}  
> > > Errors are able to propagate if called within another context that can throw, thus alleviating the annoying “catch and rethrow” behavior:
> > > 
> > > func parent() throws {  
> > > &nbsp;&nbsp;try openFile("path/to/somwhere")  
> > > }  
> > > Lastly, functions can be marked to selectively throw errors if they take a function parameter that throws with the rethrows keyword. The really interesting part is that it’s only necessary to use try when calling the function with a throwing closure.
> > > 
> > > func openFile(filename: String) throws {}  
> > > func say(message: String) {}
> > > 
> > > func sample(fn: (\_: String) throws -\> ()) rethrows {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try fn("hi")  
> > > }
> > > 
> > > try sample(openFile)  
> > > sample(say)  
> > > Converting Recoverable Errors to Domain Errors
> > > 
> > > Swift also has the try? construct. The notable thing about this construct is that it allows the caller to turn a “Recoverable Error” into a “Simple Domain Error”.
> > > 
> > > if let result = try? openFile("") {}  
> > > ErrorType Implementors
> > > 
> > > Errors are implemented using the ErrorType protocol. Since it is a protocol, new error types can be a class, a struct, or an enum. A type qualified throws clause would allow code authors to change the way that the catch-clauses need to be structured.
> > > 
> > > Enum Based ErrorType
> > > 
> > > When enums are used as the throwing mechanism, a generic catch-clause is still required as the compiler doesn’t have enough information. This leads to ambiguous code paths.
> > > 
> > > enum Errors: ErrorType {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;case OffBy1  
> > > &nbsp;&nbsp;&nbsp;&nbsp;case MutatedValue  
> > > }
> > > 
> > > func f() throws { throw Errors.OffBy1 }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try f()  
> > > }  
> > > catch Errors.OffBy1 { print("increment by 1") }  
> > > catch Errors.MutatedValue { fatalError("data corrupted") }  
> > > The above code requires a catch {} clause, but it’s ambiguous what that case should do. There is no right way to handle this error. If the error is ignored, we’re now in the land of “Logic Errors”; the code path should never be hit. If we use a fatalError() construct, then we are now in the land of converting a potential compiler error into a “Universal Error”.
> > > 
> > > Both of these are undesirable.
> > > 
> > > Struct and Class Based ErrorType
> > > 
> > > In the current design, errors that are thrown require a catch-all all the time. In the proposed design, which will be explained further, a catch-all would not be required if there was a case-clause that matched the base type.
> > > 
> > > class ErrorOne: ErrorType {}  
> > > func g() throws { throw ErrorOne() }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > > }  
> > > catch is ErrorOne { print("ErrorOne") }  
> > > The advantage in these cases are different, these cases do not allow pattern matching over the error type members (as you can in a switch-statement, for example).
> > > 
> > > The workaround for this functionality is this:
> > > 
> > > class ErrorOne: ErrorType {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > > }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > > }  
> > > catch {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;if let e = error as? ErrorOne {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch e {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 0: print("0")  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 1: print("1")  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: print("nothing")  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
> > > &nbsp;&nbsp;&nbsp;&nbsp;}  
> > > }  
> > > This proposal would turn the above into:
> > > 
> > > class ErrorOne: ErrorType {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > > }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > > }  
> > > catch \_ where error.value == 0 { print("0") }  
> > > catch \_ where error.value == 1 { print("1") }  
> > > catch { print("nothing") }  
> > > }  
> > > No gymnastics to go through, just straight-forward pattern-matching like you’d expect.
> > > 
> > > NOTE: This requires the promotion of the error constant to be allowed through the entirety of the catch-clauses.
> > > 
> > > Overriding
> > > 
> > > In the context of types, it’s completely possible to override functions with the throws annotations. The rules simply follow the rules today: covariance on the return type is allowed, contravariance is not.
> > > 
> > > Generics
> > > 
> > > When looking at generics, I cannot come up with a reason why they shouldn’t just work as normal:
> > > 
> > > func gen\<SomeError: ErrorType\>() throws SomeError {}  
> > > The only constraint would be that the specified error type must adhere to the ErrorType protocol. However, this is no different than today:
> > > 
> > > func f\<T\>(a: T) throws { throw a }  
> > > This results in the compiler error:
> > > 
> > > Thrown expression type ’T’ does not conform to ‘ErrorType’  
> > > This seems like it should “just work”.
> > > 
> > > Design Change Proposal  
> > > The design change is simple and straight-forward: allow for the annotation of the type of error that is being returned as an optional restriction. The default value would still be ErrorType.
> > > 
> > > func specific() throws MyError {}  
> > > func nonspecific() throws {}  
> > > There is a secondary result of this proposal: the error constant should be promoted to be allowed for use through-out all of the catch-clauses.
> > > 
> > > Impact on Existing Code
> > > 
> > > This is a non-breaking change. All existing constructs work today without change. That said, there are a few places where this change will have an impact on future usage.
> > > 
> > > Function Declarations
> > > 
> > > When a function has a throws clause that is attributed with a type, then that type becomes part of the function signature. This means that these two functions are not considered to be of the same type:
> > > 
> > > func one() throws {}  
> > > func two() throws NumberError {}  
> > > The function signatures are covariant though, so either one or two can be assigned to f below:
> > > 
> > > let f: () throws -\> ()  
> > > This is completely fine as NumberError still implements the ErrorType protocol.
> > > 
> > > However, in this case:
> > > 
> > > let g: () throws NumberError -\> ()  
> > > It would not be valid to assign one to g as the type signature is more specific.
> > > 
> > > throws and rethrows
> > > 
> > > Functions currently have the ability to be marked as rethrows. This basically says that if a closure parameter can throw, then the function will throw too.
> > > 
> > > func whatever(fn: () throws -\> ()) rethrows {}  
> > > The whatever function is up for anything that fn is up for. Keeping in line with this mentality, the rethrows would exhibit the same behavior: typed annotations simply apply if present and do not if they are missing.
> > > 
> > > func specific(fn: () throws HappyError -\> ()) rethrows {}  
> > > This all works as expected:
> > > 
> > > func f() throws HappyError {}  
> > > func g() {}
> > > 
> > > try specific(f)  
> > > specific(g)  
> > > This works for the same covariant reason as the non-qualified throws implementation works: a non-throwing function is always able to be passed in for a throwing function.
> > > 
> > > The do-catch statement
> > > 
> > > There are two rule changes here, but again, it’s non-breaking.
> > > 
> > > The first rule change is to promote the error constant that would normally only be allowed in the catch-all clause (no patterns) to be available throughout each of the catch clauses. This allows for the error information to be used in pattern matching, which is especially valuable in the non-enum case.
> > > 
> > > The second change is to allow the error constant to take on a specific type when all of the throwing functions throw the same specified type. When this is the case, two things become possible:
> > > 
> > > In the enum-type implementation of ErrorType, the catch-clauses can now be exhaustive.  
> > > In the all of the cases, the API of the specific ErrorType becomes available in the catch-clause without casting the error constant. This greatly simplifies the pattern-matching process.  
> > > In the case that there are heterogenous ErrorType implementations being returned, the errorconstant simply has the type of ErrorType.
> > > 
> > > The try call sites
> > > 
> > > There is no change for the try, try?, or try! uses. The only clarification I’ll add is that try?is still the appropriate way to promote an error from a “Recoverable Error” to a “Simple Domain Error”.
> > > 
> > > Alternate Proposals  
> > > There is another common error handling mechanism used in the community today: Either\<L, R\>. There are various implementations, but they all basically boil down to an enum that captures the value or the error information.
> > > 
> > > I actually consider my proposal syntactic sugar over this concept. If and when Swift supports covariant generics, there is not a significant reason I can see why the underlying implementation could not just be that.
> > > 
> > > The advantage is that the proposed (and existing) syntax of throws greatly increases the readability and understanding that this function actually possesses the ability to throw errors and they should be handled.
> > > 
> > > The other advantage of this syntax is that it doesn’t require a new construct to force the usage of the return type.
> > > 
> > > Further, if functions where to ever gain the ability to be marked as async, this could now be handled naturally within the compiler as the return type could a promise-like implementation for those.
> > > 
> > > Criticisms  
> > > From the earlier threads on the swift-evolution mailing list, there are a few primary points of contention about this proposal.
> > > 
> > > Aren’t we just creating Java checked-exceptions, which we all know are terrible?
> > > 
> > > No. The primary reason is that a function can only return a single error-type. The other major reason is that the error philosophy is very different in Swift than in Java.
> > > 
> > > Aren’t we creating fragile APIs that can cause breaking changes?
> > > 
> > > Potentially, yes. This depends on how the ABI is handled in Swift 3 for enums. The same problem exists today, although at a lesser extent, for any API that returns an enum today.
> > > 
> > > Chris Lattner mentioned this on the thread:
> > > 
> > > The resilience model addresses how the public API from a module can evolve without breaking clients (either at the source level or ABI level). Notably, we want the ability to be able to add enum cases to something by default, but also to allow API authors to opt into more performance/strictness by saying that a public enum is “fragile” or “closed for evolution”.  
> > > So if enums have an attribute that allows API authors to denote the fragility enums, then this can be handled via that route.
> > > 
> > > Another potential fix is that only internal and private scoped functions are allowed to use the exhaustive-style catch-clauses. For all public APIs, they would still need the catch-all clauses.
> > > 
> > > For APIs that return non-enum based ErrorType implementations, then no, this does not contribute to the fragility problem.
> > > 
> > > Aren’t we creating the need for wrapper errors?
> > > 
> > > This is a philosophical debate. I’ll simply state that I believe that simply re-throwing an error, say some type of IO error, from your API that is not an IO-based API is design flaw: you are exposing implementation details to users. This creates a fragile API surface.
> > > 
> > > Also, since the type annotation is opt-in, I feel like this is a really minor argument. If your function is really able to throw errors from various different API calls, then just stick with the default ErrorType.
> > > 
> > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > swift-evolution mailing list  
> > > swift-evolution@swift.org \<mailto:swift-evolution@swift.org\>  
> > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org \<mailto:swift-evolution@swift.org\>  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [December 18, 2015, 5:41pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/10 "2015-12-18T17:41:54Z")

</div>

> > 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’m not involved in the Rust community so I wouldn’t feel comfortable making claims for them.

I’m not asking for you to speak for them. But I do think we need to learn from communities that are having success with typed error handling. Your proposal would be stronger if it went into detail about how it would avoid the problems that have been encountered in other languages. The experience of Rust could help to make that case as it is concrete and not hypothetical.

> > 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).
> 
> The From() construct seems like a map(T) -\> U problem, but it seems heavily tied into the ability to create sum types. Swift doesn’t have this feature, and that feature is out-of-scope for this proposal. More on this later.

My understanding is that Rust uses static multi-dispatch to do this. I don’t believe it has anything to do with structural sum types. Rust error handling uses a Result type with a single error case: [http://doc.rust-lang.org/book/error-handling.html\](http://doc.rust-lang.org/book/error-handling.html%5C).

If you don’t believe a mechanism like this is necessary and don’t include one in your design it will lead to either a lot of boilerplate or avoidance of typed errors (depending on the developer). I think you should expect a lot of complaints about this and I think it will generate a lot of -1 votes for the proposal.

> > 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.
> 
> Sure. There’s no functionality today to auto-generate a sum type in Swift today, and that is what this request really is. If you want to return multiple return types, then you need to do exactly what Rust does and create a sum type that composes the various types of errors. This exposes the same potential fragile API surface as extending enums do. I did call this part out specifically.

How does this create a fragile API surface area? Adding a new error type to the signature would be a breaking change to the API contract. This is really no different than changing the type of error that can be thrown under your proposal.

> I see this functionality as a general limitation in the language. For example, errors are not the only context where you may want to return a type of A, B, or C. There have been other proposals on how we might do that in Swift. If and when it was solved in the general case for type parameters, I can’t foresee a compelling reason why it wouldn’t work in this context as well.

That makes sense in some ways, but I don’t think it’s unreasonable to ask for some analysis of whether a better design for typed errors would be possible if we had them. IMO it’s pretty important to get the design of typed errors right if / when we add them. If we don’t it will be considered a major mistake and will lead to a lot of less than desirable outcomes down the road.

I also think typed errors may be one of the more important use cases for structural sum types of some kind. If we are able to show that design problems that cannot be solved without them can be solved with them that might influence whether they are added or not. It might also influence when it makes sense to add support for typed errors to the language.

> > 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 guess I should have just specifically called this out in the proposal. It’s not because of “Java checked exceptions”, it’s because nowhere else in the language are types allowed to be essentially annotated in a sum-like fashion. We can’t directly say a function returns an Int or a String. We can’t say a parameter can take an Int or a Double. Similarly, I propose we can’t say a function can return an error A or B.
> 
> Thus, the primary reason is about type-system consistency.
> 
> Swift already supports a construct to create sum types: associated enums. What it doesn’t allow is the ability to create them in a syntactic shorthand. In this way, my error proposal does the same thing as Rust: multiple return types need to be combined into a single-type - enum.

That approach would make catch clauses rather clunky by nesting errors inside of associated values. If you’re advocating for this approach do you have any ideas on how to streamline syntax for catching them?

Matthew

> **···**
>
> > On Dec 18, 2015, at 10:50 AM, David Owens II \<david@owensd.io\> wrote:
> > 
> > > On Dec 18, 2015, at 5:53 AM, Matthew Johnson \<matthew@anandabits.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Felix\_Cloutier1](https://avatars.discourse-cdn.com/v4/letter/f/e47c2d/32.png) [@Felix\_Cloutier1](https://forums.swift.org/u/Felix_Cloutier1)\
**Post date:** [December 18, 2015, 5:17pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/11 "2015-12-18T17:17:06Z")

</div>

I'm not sure I understand your comment either. If I understand correctly, you say that the problem I describe is applicable only to polymorphic types (which is true). However, you then say that the only option today is polymorphic error types. Isn't that an issue? (Also, why is it the only option today?)

> **···**
>
> > Le 18 déc. 2015 à 11:58:44, David Owens II \<david@owensd.io\> a écrit :
> > 
> > > On Dec 18, 2015, at 7:03 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:
> > > 
> > > 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.
> > 
> > I don’t follow this. Declaring a type that is an enum or a struct absolutely guarantees that the function only returns a single type. If the type is a class-based error, then sure, there’s not guarantee.
> > 
> > However, the only option today is polymorphic error types.
> > 
> > -David

---

<div class="post-metadata">

**Author:** ![dennislysenko](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dennislysenko/32/41738_2.png) [@dennislysenko](https://forums.swift.org/u/dennislysenko)\
**Post date:** [December 18, 2015, 5:13pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/12 "2015-12-18T17:13:22Z")

</div>

Sorry Matthew, I think my email is having delivery issues because I didn't  
see any of those messages when I sent mine, though I see them timestamped  
before my message now.

Yes, Felix, those were valid concerns. But, as mentioned before, what we  
have now is the most polymorphic thing possible. All those functions throw  
ErrorType and that can literally be anything imaginable.

What could solve the issue is if type-annotated throws only allowed final  
(closed) classes. Also, if I'm not mistaken, enums are sealed and cannot be  
extended so they are a fantastic candidate for avoiding the proliferation  
of extending error classes. Maybe it could be limited to enums.

> **···**
>
> On Fri, Dec 18, 2015, 10:40 AM Matthew Johnson \<matthew@anandabits.com\> wrote:
> 
> > On Dec 18, 2015, at 9:25 AM, Dennis Lysenko \<dennis.s.lysenko@gmail.com\> \> wrote:
> > 
> > Genuinely, David, thank you for taking up the mantle of this problem. To  
> > me, the lack of type annotations makes the error handling painful and I  
> > wish the team just hadn't released it until the design was smoothed out  
> > fully. Those dangling catch-all blocks when I've caught all cases make it  
> > uselessly verbose and moreover do not fit with the language at all.
> > 
> > As for the multiple vs. single type annotations, I do think that you need  
> > a concrete example of why this will be different from java to quell the  
> > concerns of all the people that skim the proposal, don't think about it,  
> > and exclaim "but everyone hates it in Java!" so I agree on the singular  
> > type annotations.
> > 
> > I definitely agree that we need to address the Java problem. That said, I  
> > don’t think avoiding knee-jerk objection from people who don’t read and  
> > consider a proposal carefully is a good way to approach design. There may  
> > be good reasons to choose singular type annotations but this is not one of  
> > them.
> > 
> > I believe Félix raised good points about polymorphism and complex  
> > hierarchy causing problems in Java. That sounds like it is the source of  
> > at least a significant part of the problems with Java’s checked exception  
> > model.
> > 
> > Also, your point about being able to mark functions async strongly  
> > supports single type annotations until we get union types (if ever).
> > 
> > I am glad you addressed covariance/contravariance and the semantics of  
> > function types when they throw general errors vs. a specific one.
> > 
> > One question, mainly to the compiler team: would it be reasonable to be  
> > able to use generics covariant over the throws operator? For example, I  
> > could define a function that takes a function which throws E and returns R,  
> > and creates a function that takes a callback which takes an argument of  
> > type Either\<R, E\> instead. This would be an incredibly powerful feature.
> > 
> > On Fri, Dec 18, 2015, 8:53 AM Matthew Johnson via swift-evolution \< \> swift-evolution@swift.org\> wrote:
> > 
> > > 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@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)
> > > 
> > > —
> > > 
> > > Allow Type Annotation on Throws
> > > 
> > > &nbsp;&nbsp;&nbsp;- Proposal: SE-NNNN  
> > > &nbsp;&nbsp;&nbsp;- Author(s): David Owens II  
> > > &nbsp;&nbsp;&nbsp;- Status: \*Pending Approval for Review\*  
> > > &nbsp;&nbsp;&nbsp;- Review manager: TBD
> > > 
> > > Introduction
> > > 
> > > The error handling system within Swift today creates an implicitly loose  
> > > contract on the API. While this can be desirable in some cases, it’s  
> > > certainly not desired in \*all\* cases. This proposal looks at modifying  
> > > how the error handling mechanism works today by adding the ability to  
> > > provide a strong API contract.  
> > > Error Handling State of the Union
> > > 
> > > This document will use the terminology and the premises defined in the Error  
> > > Handling Rationale  
> > > \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt);  
> > > document.
> > > 
> > > To very briefly summarize, there are four basic classification of errors:
> > > 
> > > &nbsp;&nbsp;&nbsp;1. Simple Domain Errors  
> > > &nbsp;&nbsp;&nbsp;2. Recoverable Errors  
> > > &nbsp;&nbsp;&nbsp;3. Universal Errors  
> > > &nbsp;&nbsp;&nbsp;4. Logic Failures
> > > 
> > > Each of these types of errors are handled differently at the call sites.  
> > > Today, only the first two are directly handled by Swift error handling  
> > > mechanism. The second two are uncatchable in Swift (such as fatalError(),  
> > > ObjC exceptions, and force-unwrapping of null optionals).  
> > > Simple Domain Errors
> > > 
> > > As stated in Error Handling Rationale  
> > > \<[https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst&gt); document,  
> > > the “Swift way” to handle such errors is to return an Optional\<T\>.
> > > 
> > > func parseInt(value: String) -\> Int? {}
> > > 
> > > The simple fact of the result being Optional.None signifies that the  
> > > string could not be parsed and converted into an Int. No other  
> > > information is necessary or warranted.  
> > > Recoverable Errors
> > > 
> > > In this context, these are errors that need to provide additional  
> > > information to the caller. The caller can then decide a course of action  
> > > that needs to be taken. This could be any number of things, including, but  
> > > not limited to, logging error information, attempting a retry, or  
> > > potentially invoking a different code path. All of these errors implement  
> > > the ErrorType protocol.
> > > 
> > > func openFile(filename: String) throws {}
> > > 
> > > The throws keyword annotates that the function can return additional  
> > > error information. The caller must also explicitly make use of this when  
> > > invoking the function.
> > > 
> > > do {  
> > > &nbsp;&nbsp;try openFile("path/to/somewhere")  
> > > }  
> > > catch {}
> > > 
> > > Errors are able to propagate if called within another context that can  
> > > throw, thus alleviating the annoying “catch and rethrow” behavior:
> > > 
> > > func parent() throws {  
> > > &nbsp;&nbsp;try openFile("path/to/somwhere")  
> > > }
> > > 
> > > Lastly, functions can be marked to selectively throw errors if they take  
> > > a function parameter that throws with the rethrows keyword. The really  
> > > interesting part is that it’s only necessary to use try when calling the  
> > > function with a throwing closure.
> > > 
> > > func openFile(filename: String) throws {}  
> > > func say(message: String) {}
> > > 
> > > func sample(fn: (\_: String) throws -\> ()) rethrows {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try fn("hi")  
> > > }
> > > 
> > > try sample(openFile)  
> > > sample(say)
> > > 
> > > Converting Recoverable Errors to Domain Errors
> > > 
> > > Swift also has the try? construct. The notable thing about this  
> > > construct is that it allows the caller to turn a “Recoverable Error” into a  
> > > “Simple Domain Error”.
> > > 
> > > if let result = try? openFile("") {}
> > > 
> > > ErrorType Implementors
> > > 
> > > Errors are implemented using the ErrorType protocol. Since it is a  
> > > protocol, new error types can be a class, a struct, or an enum. A type  
> > > qualified throws clause would allow code authors to change the way that  
> > > the catch-clauses need to be structured.  
> > > Enum Based ErrorType
> > > 
> > > When enums are used as the throwing mechanism, a generic catch-clause is  
> > > still required as the compiler doesn’t have enough information. This leads  
> > > to ambiguous code paths.
> > > 
> > > enum Errors: ErrorType {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;case OffBy1  
> > > &nbsp;&nbsp;&nbsp;&nbsp;case MutatedValue  
> > > }
> > > 
> > > func f() throws { throw Errors.OffBy1 }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try f()  
> > > }  
> > > catch Errors.OffBy1 { print("increment by 1") }  
> > > catch Errors.MutatedValue { fatalError("data corrupted") }
> > > 
> > > The above code requires a catch {} clause, but it’s ambiguous what that  
> > > case should do. There is no \*right\* way to handle this error. If the  
> > > error is ignored, we’re now in the land of “Logic Errors”; the code path  
> > > should never be hit. If we use a fatalError() construct, then we are now  
> > > in the land of converting a potential compiler error into a “Universal  
> > > Error”.
> > > 
> > > Both of these are undesirable.  
> > > Struct and Class Based ErrorType
> > > 
> > > In the current design, errors that are thrown require a catch-all all the  
> > > time. In the proposed design, which will be explained further, a catch-all  
> > > would not be required if there was a case-clause that matched the base type.
> > > 
> > > class ErrorOne: ErrorType {}  
> > > func g() throws { throw ErrorOne() }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > > }  
> > > catch is ErrorOne { print("ErrorOne") }
> > > 
> > > The advantage in these cases are different, these cases do not allow  
> > > pattern matching over the error type members (as you can in a  
> > > switch-statement, for example).
> > > 
> > > The workaround for this functionality is this:
> > > 
> > > class ErrorOne: ErrorType {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > > }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > > }  
> > > catch {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;if let e = error as? ErrorOne {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch e {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 0: print("0")  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case \_ where e.value == 1: print("1")  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: print("nothing")  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
> > > &nbsp;&nbsp;&nbsp;&nbsp;}  
> > > }
> > > 
> > > This proposal would turn the above into:
> > > 
> > > class ErrorOne: ErrorType {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;let value: Int  
> > > &nbsp;&nbsp;&nbsp;&nbsp;init(\_ value: Int) { self.value = value }  
> > > }
> > > 
> > > do {  
> > > &nbsp;&nbsp;&nbsp;&nbsp;try g()  
> > > }  
> > > catch \_ where error.value == 0 { print("0") }  
> > > catch \_ where error.value == 1 { print("1") }  
> > > catch { print("nothing") }  
> > > }
> > > 
> > > No gymnastics to go through, just straight-forward pattern-matching like  
> > > you’d expect.
> > > 
> > > NOTE: This requires the promotion of the error constant to be allowed  
> > > through the entirety of the catch-clauses.  
> > > Overriding
> > > 
> > > In the context of types, it’s completely possible to override functions  
> > > with the throws annotations. The rules simply follow the rules today:  
> > > covariance on the return type is allowed, contravariance is not.  
> > > Generics
> > > 
> > > When looking at generics, I cannot come up with a reason why they  
> > > shouldn’t just work as normal:
> > > 
> > > func gen\<SomeError: ErrorType\>() throws SomeError {}
> > > 
> > > The only constraint would be that the specified error type must adhere to  
> > > the ErrorType protocol. However, this is no different than today:
> > > 
> > > func f\<T\>(a: T) throws { throw a }
> > > 
> > > This results in the compiler error:
> > > 
> > > Thrown expression type ’T’ does not conform to ‘ErrorType’
> > > 
> > > This seems like it should “just work”.  
> > > Design Change Proposal
> > > 
> > > The design change is simple and straight-forward: allow for the  
> > > annotation of the type of error that is being returned as an optional  
> > > restriction. The default value would still be ErrorType.
> > > 
> > > func specific() throws MyError {}  
> > > func nonspecific() throws {}
> > > 
> > > There is a secondary result of this proposal: the error constant should  
> > > be promoted to be allowed for use through-out all of the catch-clauses.  
> > > Impact on Existing Code
> > > 
> > > This is a non-breaking change. All existing constructs work today without  
> > > change. That said, there are a few places where this change will have an  
> > > impact on future usage.  
> > > Function Declarations
> > > 
> > > When a function has a throws clause that is attributed with a type, then  
> > > that type becomes part of the function signature. This means that these two  
> > > functions are not considered to be of the same type:
> > > 
> > > func one() throws {}  
> > > func two() throws NumberError {}
> > > 
> > > The function signatures are covariant though, so either one or two can  
> > > be assigned to f below:
> > > 
> > > let f: () throws -\> ()
> > > 
> > > This is completely fine as NumberError still implements the ErrorType  
> > > protocol.
> > > 
> > > However, in this case:
> > > 
> > > let g: () throws NumberError -\> ()
> > > 
> > > It would not be valid to assign one to g as the type signature is more  
> > > specific.  
> > > throws and rethrows
> > > 
> > > Functions currently have the ability to be marked as rethrows. This  
> > > basically says that if a closure parameter can throw, then the function  
> > > will throw too.
> > > 
> > > func whatever(fn: () throws -\> ()) rethrows {}
> > > 
> > > The whatever function is up for anything that fn is up for. Keeping in  
> > > line with this mentality, the rethrows would exhibit the same behavior:  
> > > typed annotations simply apply if present and do not if they are missing.
> > > 
> > > func specific(fn: () throws HappyError -\> ()) rethrows {}
> > > 
> > > This all works as expected:
> > > 
> > > func f() throws HappyError {}  
> > > func g() {}
> > > 
> > > try specific(f)  
> > > specific(g)
> > > 
> > > This works for the same covariant reason as the non-qualified throws implementation  
> > > works: a non-throwing function is always able to be passed in for a  
> > > throwing function.  
> > > The do-catch statement
> > > 
> > > There are two rule changes here, but again, it’s non-breaking.
> > > 
> > > The first rule change is to promote the error constant that would  
> > > normally only be allowed in the catch-all clause (no patterns) to be  
> > > available throughout each of the catch clauses. This allows for the error  
> > > information to be used in pattern matching, which is especially valuable in  
> > > the non-enum case.
> > > 
> > > The second change is to allow the error constant to take on a specific  
> > > type when \*all\* of the throwing functions throw the same specified type.  
> > > When this is the case, two things become possible:
> > > 
> > > &nbsp;&nbsp;&nbsp;1. In the enum-type implementation of ErrorType, the catch-clauses  
> > > &nbsp;&nbsp;&nbsp;can now be exhaustive.  
> > > &nbsp;&nbsp;&nbsp;2. In the all of the cases, the API of the specific ErrorType becomes  
> > > &nbsp;&nbsp;&nbsp;available in the catch-clause without casting the error constant.  
> > > &nbsp;&nbsp;&nbsp;This greatly simplifies the pattern-matching process.
> > > 
> > > In the case that there are heterogenous ErrorType implementations being  
> > > returned, the errorconstant simply has the type of ErrorType.  
> > > The try call sites
> > > 
> > > There is no change for the try, try?, or try! uses. The only  
> > > clarification I’ll add is that try?is still the appropriate way to  
> > > promote an error from a “Recoverable Error” to a “Simple Domain Error”.  
> > > Alternate Proposals
> > > 
> > > There is another common error handling mechanism used in the community  
> > > today: Either\<L, R\>. There are various implementations, but they all  
> > > basically boil down to an enum that captures the value or the error  
> > > information.
> > > 
> > > I actually consider my proposal syntactic sugar over this concept. If and  
> > > when Swift supports covariant generics, there is not a significant reason I  
> > > can see why the underlying implementation could not just be that.
> > > 
> > > The advantage is that the proposed (and existing) syntax of throws greatly  
> > > increases the readability and understanding that this function actually  
> > > possesses the ability to throw errors and they should be handled.
> > > 
> > > The other advantage of this syntax is that it doesn’t require a new  
> > > construct to force the usage of the return type.
> > > 
> > > Further, if functions where to ever gain the ability to be marked as  
> > > async, this could now be handled naturally within the compiler as the  
> > > return type could a promise-like implementation for those.  
> > > Criticisms
> > > 
> > > From the earlier threads on the swift-evolution mailing list, there are a  
> > > few primary points of contention about this proposal.  
> > > Aren’t we just creating Java checked-exceptions, which we all know are  
> > > terrible?
> > > 
> > > No. The primary reason is that a function can only return a single  
> > > error-type. The other major reason is that the error philosophy is very  
> > > different in Swift than in Java.  
> > > Aren’t we creating fragile APIs that can cause breaking changes?
> > > 
> > > Potentially, yes. This depends on how the ABI is handled in Swift 3 for  
> > > enums. The same problem exists today, although at a lesser extent, for any  
> > > API that returns an enum today.
> > > 
> > > Chris Lattner mentioned this on the thread:
> > > 
> > > The resilience model addresses how the public API from a module can  
> > > evolve without breaking clients (either at the source level or ABI level).  
> > > Notably, we want the ability to be able to add enum cases to something by  
> > > default, but also to allow API authors to opt into more  
> > > performance/strictness by saying that a public enum is “fragile” or “closed  
> > > for evolution”.
> > > 
> > > So if enums have an attribute that allows API authors to denote the  
> > > fragility enums, then this can be handled via that route.
> > > 
> > > Another potential fix is that \*only\* internal and private scoped  
> > > functions are allowed to use the exhaustive-style catch-clauses. For all  
> > > public APIs, they would still need the catch-all clauses.
> > > 
> > > For APIs that return non-enum based ErrorType implementations, then no,  
> > > this does not contribute to the fragility problem.  
> > > Aren’t we creating the need for wrapper errors?
> > > 
> > > This is a philosophical debate. I’ll simply state that I believe that  
> > > simply re-throwing an error, say some type of IO error, from your API that  
> > > is not an IO-based API is design flaw: you are exposing implementation  
> > > details to users. This creates a fragile API surface.
> > > 
> > > Also, since the type annotation is opt-in, I feel like this is a really  
> > > minor argument. If your function is really able to throw errors from  
> > > various different API calls, then just stick with the default ErrorType.  
> > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > swift-evolution mailing list  
> > > swift-evolution@swift.org  
> > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)
> > > 
> > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > swift-evolution mailing list  
> > > swift-evolution@swift.org  
> > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![Alex\_Popov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alex_popov/32/5300_2.png) [@Alex\_Popov](https://forums.swift.org/u/Alex_Popov)\
**Post date:** [December 18, 2015, 6:29pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/13 "2015-12-18T18:29:02Z")

</div>

Hi all,

I am very much pro this addition, if for nothing else than more information  
for the developer using the API.

Limiting `throws MyErrorType` to only Enums, Structs and final Classes gets  
around the Java problems so far as I can see.

As for the usefulness of this, I'm working on a fairly large project, and the  
only way of documenting what errors can be thrown is through documentation  
comments, which must then be maintained — there is little worse than incorrect  
/out-of-date documentation. Although currently the catch-all is mandated,  
guaranteeing safety, as a developer I'm equally concerned about recovering  
from an error: without knowing exactly which Enum can be thrown, or what  
subset of cases can occur, I either have to navigate to the source code and go  
down the rabbit hole of tracking that information down, or just accepting that  
I don't know what'll be thrown (and thereby potentially not recovering from a  
recoverable failure).

I find it really frustrating that the compiler is unable to help me out with  
this, even though in certain cases I \_can\_ guarantee what will be thrown. If  
this proposal also brings about more convenient pattern matching for error  
handling, that's a +2 from me.

\<br

> **···**
>
> —
> 
> \<br
> 
> Alex Popov Jr.
> 
> Principal iOS Developer | Shelfie
> 
> > On Dec 18 2015, at 9:42 am, Matthew Johnson via swift-evolution &lt;swift- evolution@swift.org&gt; wrote:  
> > &nbsp;&nbsp;
> > 
> > > On Dec 18, 2015, at 10:50 AM, David Owens II &lt;[david@owensd.io](mailto:david@owensd.io)&gt; wrote:
> 
> > > > On Dec 18, 2015, at 5:53 AM, Matthew Johnson &lt;[matthew@anandabits.com](mailto:matthew@anandabits.com)&gt; wrote:  
> > > > &nbsp;&nbsp;  
> > > > David,  
> > > > &nbsp;&nbsp;  
> > > > 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.  
> > > > &nbsp;&nbsp;  
> > > > 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’m not involved in the Rust community so I wouldn’t feel comfortable making  
> claims for them.
> 
> > I’m not asking for you to speak for them. But I do think we need to learn
> 
> from communities that are having success with typed error handling. Your  
> proposal would be stronger if it went into detail about how it would avoid the  
> problems that have been encountered in other languages. The experience of  
> Rust could help to make that case as it is concrete and not hypothetical.
> 
> > > > 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).
> 
> The From() construct seems like a map(T) -&gt; U problem, but it seems heavily  
> tied into the ability to create sum types. Swift doesn’t have this feature,  
> and that feature is out-of-scope for this proposal. More on this later.
> 
> > My understanding is that Rust uses static multi-dispatch to do this. I
> 
> don’t believe it has anything to do with structural sum types. Rust error  
> handling uses a Result type with a single error case: \<http://doc.rust-  
> lang.org/book/error-handling.html\>.
> 
> > If you don’t believe a mechanism like this is necessary and don’t include
> 
> one in your design it will lead to either a lot of boilerplate or avoidance of  
> typed errors (depending on the developer). I think you should expect a lot of  
> complaints about this and I think it will generate a lot of -1 votes for the  
> proposal.
> 
> > > > 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.
> 
> Sure. There’s no functionality today to auto-generate a sum type in Swift  
> today, and that is what this request really is. If you want to return multiple  
> return types, then you need to do exactly what Rust does and create a sum type  
> that composes the various types of errors. This exposes the same potential  
> fragile API surface as extending enums do. I did call this part out  
> specifically.
> 
> > How does this create a fragile API surface area? Adding a new error type to
> 
> the signature would be a breaking change to the API contract. This is really  
> no different than changing the type of error that can be thrown under your  
> proposal.
> 
> > > I see this functionality as a general limitation in the language. For
> 
> example, errors are not the only context where you may want to return a type  
> of A, B, or C. There have been other proposals on how we might do that in  
> Swift. If and when it was solved in the general case for type parameters, I  
> can’t foresee a compelling reason why it wouldn’t work in this context as  
> well.
> 
> > That makes sense in some ways, but I don’t think it’s unreasonable to ask
> 
> for some analysis of whether a better design for typed errors would be  
> possible if we had them. IMO it’s pretty important to get the design of typed  
> errors right if / when we add them. If we don’t it will be considered a major  
> mistake and will lead to a lot of less than desirable outcomes down the road.
> 
> > I also think typed errors may be one of the more important use cases for
> 
> structural sum types of some kind. If we are able to show that design  
> problems that \*\*cannot\*\* be solved without them \*\*can\*\* be solved with them  
> that might influence whether they are added or not. It might also influence  
> \*\*when\*\* it makes sense to add support for typed errors to the language.
> 
> > > > 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 guess I should have just specifically called this out in the proposal. It’s  
> not because of “Java checked exceptions”, it’s because nowhere else in the  
> language are types allowed to be essentially annotated in a sum-like fashion.  
> We can’t directly say a function returns an Int or a String. We can’t say a  
> parameter can take an Int or a Double. Similarly, I propose we can’t say a  
> function can return an error A or B.  
> &nbsp;&nbsp;  
> Thus, the primary reason is about type-system consistency.  
> &nbsp;&nbsp;  
> Swift already supports a construct to create sum types: associated enums. What  
> it doesn’t allow is the ability to create them in a syntactic shorthand. In  
> this way, my error proposal does the same thing as Rust: multiple return types  
> need to be combined into a single-type - enum.
> 
> > That approach would make catch clauses rather clunky by nesting errors
> 
> inside of associated values. If you’re advocating for this approach do you  
> have any ideas on how to streamline syntax for catching them?
> 
> > Matthew
> 
> > !([https://u2002410.ct.sendgrid.net/wf/open?upn=CmwAv3oRa0AH4Hd1bWC6X-](https://u2002410.ct.sendgrid.net/wf/open?upn=CmwAv3oRa0AH4Hd1bWC6X-)
> 
> 2BzbhPqo1YEo6mPHEujr90vUljsud-2BB6KUDP5cz-  
> 2Fv0xXzcKh2I7l3AVBGsasABqpSVQZA47MBrZnIRbuczKfFabYpw7SI-2FEE3vWg8ZsRzYrusFrkP3  
> -2Fdfov48EZIMr1UIxRUjZjSkWFw5gJSpy8pL-2Fo1jlRzHx1-2B7tEBTDx1EdAI9LfCCL-  
> 2FD4vOGJSJXCTPis0shiFWB5ZEKHAD1LQ3af20-3D)

---

<div class="post-metadata">

**Author:** ![owensd](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owensd/32/8934_2.png) [@owensd](https://forums.swift.org/u/owensd)\
**Post date:** [December 18, 2015, 6:36pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/14 "2015-12-18T18:36:17Z")

</div>

> I’m not asking for you to speak for them. But I do think we need to learn from communities that are having success with typed error handling. Your proposal would be stronger if it went into detail about how it would avoid the problems that have been encountered in other languages. The experience of Rust could help to make that case as it is concrete and not hypothetical.

Sure, it could. It’s also anecdotal. It’s not necessarily true that something that works well in one context works well in another. It’s good to note that typed errors are wholly considered bad, but I’m not sure how much further we need to go then that. If you have specifics, then I could probably add them as an addendum to the proposal.

> My understanding is that Rust uses static multi-dispatch to do this. I don’t believe it has anything to do with structural sum types. Rust error handling uses a Result type with a single error case: [http://doc.rust-lang.org/book/error-handling.html\](http://doc.rust-lang.org/book/error-handling.html%5C).

That example takes you through many of the options available. In the end, you end up at the sum-type for the error:  
fn search\<P: AsRef\<Path\>\>  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(file\_path: &Option\<P\>, city: &str)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-\> Result\<Vec\<PopulationCount\>, CliError\> {  
&nbsp;&nbsp;&nbsp;&nbsp;...  
}  
It’s the CliError which is defined as:  
enum CliError {  
&nbsp;&nbsp;&nbsp;&nbsp;Io(io::Error),  
&nbsp;&nbsp;&nbsp;&nbsp;Csv(csv::Error),  
&nbsp;&nbsp;&nbsp;&nbsp;NotFound,  
}  
The From() function essentially allows the try! macro to expand these in a nicer way.

So back to the proposal, one of the key things is to promote the `error` constant throughout the catch-clauses. This means that we can already leverage Swift’s pattern matching to solve this problem:

enum Combined {  
&nbsp;&nbsp;&nbsp;&nbsp;case IO(String)  
&nbsp;&nbsp;&nbsp;&nbsp;case Number(Int)  
}

func simulate(err: Combined) {  
&nbsp;&nbsp;&nbsp;&nbsp;switch err {  
&nbsp;&nbsp;&nbsp;&nbsp;case let Combined.IO(string) where string == "hi": print("only hi!")  
&nbsp;&nbsp;&nbsp;&nbsp;case let Combined.IO(string): print(string)  
&nbsp;&nbsp;&nbsp;&nbsp;case let Combined.Number(value): print(value)  
&nbsp;&nbsp;&nbsp;&nbsp;}  
}

simulate(Combined.IO("hi"))  
simulate(Combined.IO("io"))  
simulate(Combined.Number(9))

It’s not hard to use Swift’s pattern matching to extract out the inner information on an associated value enum and white the case/catch clauses. So unless I’m missing something, I think Swift already provides a good mechanism to do what you’re asking for, with the caveat that the `error` constant is promoted to be usable in the catch-clauses similar to how the switch-statements work.

Maybe adding this to the proposal would clarify usage?

> How does this create a fragile API surface area? Adding a new error type to the signature would be a breaking change to the API contract. This is really no different than changing the type of error that can be thrown under your proposal.

It’s the same fragility that enums create; this was covered in the criticisms section. The likelihood of adding additional error cases is much greater than a change that would completely change the type of the error.

> > I see this functionality as a general limitation in the language. For example, errors are not the only context where you may want to return a type of A, B, or C. There have been other proposals on how we might do that in Swift. If and when it was solved in the general case for type parameters, I can’t foresee a compelling reason why it wouldn’t work in this context as well.
> 
> That makes sense in some ways, but I don’t think it’s unreasonable to ask for some analysis of whether a better design for typed errors would be possible if we had them. IMO it’s pretty important to get the design of typed errors right if / when we add them. If we don’t it will be considered a major mistake and will lead to a lot of less than desirable outcomes down the road.
> 
> I also think typed errors may be one of the more important use cases for structural sum types of some kind. If we are able to show that design problems that cannot be solved without them can be solved with them that might influence whether they are added or not. It might also influence when it makes sense to add support for typed errors to the language.

The problem can be solved without implicitly generated sum types though. The design of typed errors, as proposed, is to be consistent with the Swift type system today. Regardless, I’ve added a response in the “cirticisms” section that hopefully addresses this in some manner - basically, yes it would be helpful, but out of scope for this proposal.

> That approach would make catch clauses rather clunky by nesting errors inside of associated values. If you’re advocating for this approach do you have any ideas on how to streamline syntax for catching them?

See above example. Does that address this concern?

-David

> **···**
>
> > On Dec 18, 2015, at 9:41 AM, Matthew Johnson \<matthew@anandabits.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Felix\_Cloutier1](https://avatars.discourse-cdn.com/v4/letter/f/e47c2d/32.png) [@Felix\_Cloutier1](https://forums.swift.org/u/Felix_Cloutier1)\
**Post date:** [December 18, 2015, 5:21pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/15 "2015-12-18T17:21:32Z")

</div>

Oh, I see what you mean. I considered polymorphic types to be class hierarchies, when you're talking about ErrorType polymorphism.

Yes, I think that the compiler should be aware of what the function can throw, but I would be happier if it stayed a bit inconvenient to use reference types.

> **···**
>
> > Le 18 déc. 2015 à 12:17:06, Félix Cloutier via swift-evolution \<swift-evolution@swift.org\> a écrit :
> > 
> > I'm not sure I understand your comment either. If I understand correctly, you say that the problem I describe is applicable only to polymorphic types (which is true). However, you then say that the only option today is polymorphic error types. Isn't that an issue? (Also, why is it the only option today?)
> > 
> > > Le 18 déc. 2015 à 11:58:44, David Owens II \<david@owensd.io\> a écrit :
> > > 
> > > > On Dec 18, 2015, at 7:03 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:
> > > > 
> > > > 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.
> > > 
> > > I don’t follow this. Declaring a type that is an enum or a struct absolutely guarantees that the function only returns a single type. If the type is a class-based error, then sure, there’s not guarantee.
> > > 
> > > However, the only option today is polymorphic error types.
> > > 
> > > -David
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![rparada](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rparada/32/967_2.png) [@rparada](https://forums.swift.org/u/rparada)\
**Post date:** [December 19, 2015, 12:38am UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/16 "2015-12-19T00:38:41Z")

</div>

Hi David

I started reading your proposal and I have a couple of questions.

In the Enum Base ErrorType example you mentioned that it requires a "catch { }" clause. However the code is already covering the two possible Enum values (OffBy1 and MutatedValue). Why is the "catch { }" required? I typed that code into a playground and I did not get any errors. Are you saying that because the Enum type could add a value in the future?

Also, you proposed the catch clause to use error as the name of the constant holding the error. Wouldn't it be better to let the programmer decide the name rather than hard coding it to use error? For example:

catch e where e.value == 0 { print("0") }  
catch e where e.value == 1 { print("1") }  
catch { print("nothing") }

Thank you  
Ricardo

> **···**
>
> Sent from my iPhone
> 
> > On Dec 18, 2015, at 1:36 PM, David Owens II via swift-evolution \<swift-evolution@swift.org\> wrote:
> > 
> > > On Dec 18, 2015, at 9:41 AM, Matthew Johnson \<matthew@anandabits.com\> wrote:
> > > 
> > > I’m not asking for you to speak for them. But I do think we need to learn from communities that are having success with typed error handling. Your proposal would be stronger if it went into detail about how it would avoid the problems that have been encountered in other languages. The experience of Rust could help to make that case as it is concrete and not hypothetical.
> > 
> > Sure, it could. It’s also anecdotal. It’s not necessarily true that something that works well in one context works well in another. It’s good to note that typed errors are wholly considered bad, but I’m not sure how much further we need to go then that. If you have specifics, then I could probably add them as an addendum to the proposal.
> > 
> > > My understanding is that Rust uses static multi-dispatch to do this. I don’t believe it has anything to do with structural sum types. Rust error handling uses a Result type with a single error case: [http://doc.rust-lang.org/book/error-handling.html\](http://doc.rust-lang.org/book/error-handling.html%5C).
> > 
> > That example takes you through many of the options available. In the end, you end up at the sum-type for the error:  
> > fn search\<P: AsRef\<Path\>\>  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(file\_path: &Option\<P\>, city: &str)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-\> Result\<Vec\<PopulationCount\>, CliError\> {  
> > &nbsp;&nbsp;&nbsp;&nbsp;...  
> > }  
> > It’s the CliError which is defined as:  
> > enum CliError {  
> > &nbsp;&nbsp;&nbsp;&nbsp;Io(io::Error),  
> > &nbsp;&nbsp;&nbsp;&nbsp;Csv(csv::Error),  
> > &nbsp;&nbsp;&nbsp;&nbsp;NotFound,  
> > }  
> > The From() function essentially allows the try! macro to expand these in a nicer way.
> > 
> > So back to the proposal, one of the key things is to promote the `error` constant throughout the catch-clauses. This means that we can already leverage Swift’s pattern matching to solve this problem:
> > 
> > enum Combined {  
> > &nbsp;&nbsp;&nbsp;&nbsp;case IO(String)  
> > &nbsp;&nbsp;&nbsp;&nbsp;case Number(Int)  
> > }
> > 
> > func simulate(err: Combined) {  
> > &nbsp;&nbsp;&nbsp;&nbsp;switch err {  
> > &nbsp;&nbsp;&nbsp;&nbsp;case let Combined.IO(string) where string == "hi": print("only hi!")  
> > &nbsp;&nbsp;&nbsp;&nbsp;case let Combined.IO(string): print(string)  
> > &nbsp;&nbsp;&nbsp;&nbsp;case let Combined.Number(value): print(value)  
> > &nbsp;&nbsp;&nbsp;&nbsp;}  
> > }
> > 
> > simulate(Combined.IO("hi"))  
> > simulate(Combined.IO("io"))  
> > simulate(Combined.Number(9))
> > 
> > It’s not hard to use Swift’s pattern matching to extract out the inner information on an associated value enum and white the case/catch clauses. So unless I’m missing something, I think Swift already provides a good mechanism to do what you’re asking for, with the caveat that the `error` constant is promoted to be usable in the catch-clauses similar to how the switch-statements work.
> > 
> > Maybe adding this to the proposal would clarify usage?
> > 
> > > How does this create a fragile API surface area? Adding a new error type to the signature would be a breaking change to the API contract. This is really no different than changing the type of error that can be thrown under your proposal.
> > 
> > It’s the same fragility that enums create; this was covered in the criticisms section. The likelihood of adding additional error cases is much greater than a change that would completely change the type of the error.
> > 
> > > > I see this functionality as a general limitation in the language. For example, errors are not the only context where you may want to return a type of A, B, or C. There have been other proposals on how we might do that in Swift. If and when it was solved in the general case for type parameters, I can’t foresee a compelling reason why it wouldn’t work in this context as well.
> > > 
> > > That makes sense in some ways, but I don’t think it’s unreasonable to ask for some analysis of whether a better design for typed errors would be possible if we had them. IMO it’s pretty important to get the design of typed errors right if / when we add them. If we don’t it will be considered a major mistake and will lead to a lot of less than desirable outcomes down the road.
> > > 
> > > I also think typed errors may be one of the more important use cases for structural sum types of some kind. If we are able to show that design problems that cannot be solved without them can be solved with them that might influence whether they are added or not. It might also influence when it makes sense to add support for typed errors to the language.
> > 
> > The problem can be solved without implicitly generated sum types though. The design of typed errors, as proposed, is to be consistent with the Swift type system today. Regardless, I’ve added a response in the “cirticisms” section that hopefully addresses this in some manner - basically, yes it would be helpful, but out of scope for this proposal.
> > 
> > > That approach would make catch clauses rather clunky by nesting errors inside of associated values. If you’re advocating for this approach do you have any ideas on how to streamline syntax for catching them?
> > 
> > See above example. Does that address this concern?
> > 
> > -David
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [December 21, 2015, 2:36pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/17 "2015-12-21T14:36:56Z")

</div>

Hi David,

I spent a lot of time last night thinking about how my concerns can be addressed without changes to the type system. I also spent some time working through some concrete examples this morning. This has helped narrow my concerns considerably.

I am going to suggest one addition to the proposal at the end. If you’re willing to incorporate that I will be pretty happy with what we can accomplish without any changes to the type system.

First, consider the case where there are some common errors which a library may throw in different places. These are considered to be part of the API contract. Some library functions may throw either common error depending on the code path taken.

Your proposal suggests we should fall back to throwing ErrorType in that case. This is not really a good solution in my mind.

A library should be able to have a family of error types it publishes in its API contract and some functions should be able to throw more than one. As you suggest, rather than a structural sum type we can manually create a sum type to do this.

I had two concerns about this. The first and most important was in the verbosity of catching the nested errors. Here’s an example:

enum CommonOne: ErrorType {  
&nbsp;&nbsp;&nbsp;&nbsp;case One  
&nbsp;&nbsp;&nbsp;&nbsp;case Two  
}  
enum CommonTwo:ErrorType {  
&nbsp;&nbsp;&nbsp;&nbsp;case One  
&nbsp;&nbsp;&nbsp;&nbsp;case Two  
}  
enum Both: ErrorType {  
&nbsp;&nbsp;&nbsp;&nbsp;case One(CommonOne)  
&nbsp;&nbsp;&nbsp;&nbsp;case Two(CommonTwo)  
}

I was concerned that we would need to do something like this involving some verbose and nasty nesting, etc:

func functionThatThrowsBoth() throws Both { … }

do {  
&nbsp;&nbsp;&nbsp;&nbsp;try functionThatThrowsBoth()  
}  
catch .One(let inner) {  
&nbsp;&nbsp;&nbsp;&nbsp;switch inner {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case .one: ...  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case .two: ...  
&nbsp;&nbsp;&nbsp;&nbsp;}  
}  
catch .Two(let inner) {  
&nbsp;&nbsp;&nbsp;&nbsp;switch inner {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case .one: ...  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case .two: ...  
&nbsp;&nbsp;&nbsp;&nbsp;}  
}

As it turns out, I am still getting familiar with the power of nested pattern matching and this was an unfounded concern. This is great! We can actually do this:

do {  
&nbsp;&nbsp;&nbsp;&nbsp;try functionThatThrowsBoth()  
}  
catch .One(.One) { ... }  
catch .One(.Two) { ... }  
catch .Two(.One) { ... }  
catch .Two(.Two) { ... }

(note: this works today if you include a Both prefix in the cases which will be unnecessary with a typed error)

That is great! I have no concerns about this syntax for catching nested errors. This covers use cases that need to throw “multiple” error types pretty well. There are probably some edge cases where a structural sum type would be more convenient but I think they would be rare and am not concerned about them.

I would also like to comment that there are some interesting related ideas for enhancing enums in the "[Pitch] Use enums as enum underlying types” thread. They don’t directly impact the proposal but could make such use cases even more convenient if they are pursued independently.

The other concern I have is still valid, but I think a relatively straightforward solution is possible.

Continuing with the previous example, let’s look at the implementation of `functionThatThrowsBoth`:

func throwsInnerOne() throws InnerOne {  
&nbsp;&nbsp;&nbsp;&nbsp;throw InnerOne.One  
}

func throwsInnerTwo() throws InnerTwo {  
&nbsp;&nbsp;&nbsp;&nbsp;throw InnerTwo.Two  
}

func functionThatThrowsBoth(\_ whichError: Bool) throws Both {  
&nbsp;&nbsp;&nbsp;&nbsp;do {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if whichError {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try throwsInnerOne()  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try throwsInnerTwo()  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;catch let inner as InnerOne { throw Both.One(inner) }  
&nbsp;&nbsp;&nbsp;&nbsp;catch let inner as InnerTwo { throw Both.Two(inner) }  
}

The implementation is dominated by the concern of wrapping the error. This is pretty gross. This problem exists even if we are not wrapping the error, but rather translating the error from the underlying error type into the error type we are publishing in our API contract.

Here is an example where we are not wrapping the error, but translating it:

func functionThatCallsUnderlingyingThrows(\_ whichError: Bool) throws MyPublishedError {  
&nbsp;&nbsp;&nbsp;&nbsp;do {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try funcThatThrowsAnErrorThatMustBeTranslatedIntoMyPublishedError()  
&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;// catching logic that eventually throws MyPublishedErrorSomehow  
}

The best we can do is to create a translation function or initializer:

enum MyPublishedError: ErrorType {  
&nbsp;&nbsp;&nbsp;&nbsp;init(\_ error: UnderlyingError) { … }  
}

func functionThatCallsUnderlingyingThrows(\_ whichError: Bool) throws MyPublishedError {  
&nbsp;&nbsp;&nbsp;&nbsp;do {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try funcThatThrowsAnErrorThatMustBeTranslatedIntoMyPublishedError()  
&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;catch let error as UnderlyingError { throw MyPublishedError(error) }  
}

This is better as it removes the logic from the function itself. But it’s still not great as it introduces a lot of boilerplate everywhere we need to translate and / or wrap errors. The boilerplate also grows for each underlying error we need to translate:

func functionThatCallsUnderlingyingThrows(\_ whichError: Bool) throws MyPublishedError {  
&nbsp;&nbsp;&nbsp;&nbsp;do {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// bunch of stuff throwing several different errors  
&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;catch let error as UnderlyingError { throw MyPublishedError(error) }  
&nbsp;&nbsp;&nbsp;&nbsp;catch let error as OtherUnderlyingError { throw MyPublishedError(error) }  
&nbsp;&nbsp;&nbsp;&nbsp;// more catch clauses until we have covered every possible error type thrown by the body  
&nbsp;&nbsp;&nbsp;&nbsp;// hopefully the compiler wouldn’t require a default clause here but it probably would  
}

This is the problem that `From` addresses in Rust. Swift is not Rust and our solution will look different. The point is that this is a problem and it can and has been solved.

My suggestion is that we should allow implicit conversion during error propagation. If the published error type has one and only one non-failable, non-throwing initializer that takes a single argument of the type that is thrown (including enum case initializers with a single associated value of the thrown type) that initializer is used to implicitly convert to the published error type. This conversion could be accomplished by synthesizing the necessary boilerplate or by some other means.

Now we have:

func functionThatCallsUnderlingyingThrows(\_ whichError: Bool) throws MyPublishedError {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try funcThatThrowsAnErrorThatMustBeTranslatedIntoMyPublishedError()  
}

This looks as it should. We don’t pay a price of boilerplate for carefully designing the errors we expose in our API contract. This also handles automatic wrapping of errors where that is appropriate.

I don’t suggest implicit conversion lightly. I generally hate implicit conversions. But I think it makes a lot of sense here. It keeps concerns separate and removes boilerplate that distracts from the logic at hand, thus vastly improving readability. It is also likely to help minimize code impact when implementation details change and we need to modify how we are translating errors into the contract we expose.

If we don’t support the implicit conversion there are three paths that can be taken by developers. None of them are great and we will have three camps with different preference:

1. Just stick to untyped errors. I think there are some pretty smart people who think this will be a common practice even if we have support for typed errors in the language.  
2. Allow underlying errors to flow through (when there is only a single underlying error type). This is brittle and I know you are of the opinion that it is a bad idea. I agree.  
3. Write the boilerplate manually. This is annoying and is a significant barrier to clarity and readability.

I hope you will like the idea of implicit conversion during error propagation enough to add it to your proposal. With it I will be an enthusiastic supporter. It will help to establish good practices in the community for using typed errors in a robust and thoughtful way.

Without implicit error conversion I will still support the proposal but would plan to write a follow on proposal introducing the much needed (IMO) implicit conversion during error propagation. I would also expect opposition to the proposal during review from people concerned about one or more of the above listed options for dealing with error translation.

I think the idea of restricting typed errors to structs, enums, NSError, and final classes that has come up is a good one. It might be worth considering going further than that and restrict it to only enums and NSError. One of the biggest issues I have encountered with error handling during my career is that all too often the possible error cases are quite poorly documented. We have to allow NSError for Cocoa interop, but aside from the error types should really be enums IMO as they make it very clear what cases might need to be handled.

I want to thank you again for putting this proposal together and taking the time to consider and respond to feedback. Typed errors will be a significant step forward for Swift and I am looking forward to it.

Matthew

> **···**
>
> > On Dec 18, 2015, at 12:36 PM, David Owens II \<david@owensd.io\> wrote:
> > 
> > > On Dec 18, 2015, at 9:41 AM, Matthew Johnson \<matthew@anandabits.com \<mailto:matthew@anandabits.com\>\> wrote:
> > > 
> > > I’m not asking for you to speak for them. But I do think we need to learn from communities that are having success with typed error handling. Your proposal would be stronger if it went into detail about how it would avoid the problems that have been encountered in other languages. The experience of Rust could help to make that case as it is concrete and not hypothetical.
> > 
> > Sure, it could. It’s also anecdotal. It’s not necessarily true that something that works well in one context works well in another. It’s good to note that typed errors are wholly considered bad, but I’m not sure how much further we need to go then that. If you have specifics, then I could probably add them as an addendum to the proposal.
> > 
> > > My understanding is that Rust uses static multi-dispatch to do this. I don’t believe it has anything to do with structural sum types. Rust error handling uses a Result type with a single error case: [http://doc.rust-lang.org/book/error-handling.html\](http://doc.rust-lang.org/book/error-handling.html%5C).
> > 
> > That example takes you through many of the options available. In the end, you end up at the sum-type for the error:  
> > fn search\<P: AsRef\<Path\>\>  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(file\_path: &Option\<P\>, city: &str)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-\> Result\<Vec\<PopulationCount\>, CliError\> {  
> > &nbsp;&nbsp;&nbsp;&nbsp;...  
> > }  
> > It’s the CliError which is defined as:  
> > enum CliError {  
> > &nbsp;&nbsp;&nbsp;&nbsp;Io(io::Error),  
> > &nbsp;&nbsp;&nbsp;&nbsp;Csv(csv::Error),  
> > &nbsp;&nbsp;&nbsp;&nbsp;NotFound,  
> > }  
> > The From() function essentially allows the try! macro to expand these in a nicer way.
> > 
> > So back to the proposal, one of the key things is to promote the `error` constant throughout the catch-clauses. This means that we can already leverage Swift’s pattern matching to solve this problem:
> > 
> > enum Combined {  
> > &nbsp;&nbsp;&nbsp;&nbsp;case IO(String)  
> > &nbsp;&nbsp;&nbsp;&nbsp;case Number(Int)  
> > }
> > 
> > func simulate(err: Combined) {  
> > &nbsp;&nbsp;&nbsp;&nbsp;switch err {  
> > &nbsp;&nbsp;&nbsp;&nbsp;case let Combined.IO(string) where string == "hi": print("only hi!")  
> > &nbsp;&nbsp;&nbsp;&nbsp;case let Combined.IO(string): print(string)  
> > &nbsp;&nbsp;&nbsp;&nbsp;case let Combined.Number(value): print(value)  
> > &nbsp;&nbsp;&nbsp;&nbsp;}  
> > }
> > 
> > simulate(Combined.IO("hi"))  
> > simulate(Combined.IO("io"))  
> > simulate(Combined.Number(9))
> > 
> > It’s not hard to use Swift’s pattern matching to extract out the inner information on an associated value enum and white the case/catch clauses. So unless I’m missing something, I think Swift already provides a good mechanism to do what you’re asking for, with the caveat that the `error` constant is promoted to be usable in the catch-clauses similar to how the switch-statements work.
> > 
> > Maybe adding this to the proposal would clarify usage?
> > 
> > > How does this create a fragile API surface area? Adding a new error type to the signature would be a breaking change to the API contract. This is really no different than changing the type of error that can be thrown under your proposal.
> > 
> > It’s the same fragility that enums create; this was covered in the criticisms section. The likelihood of adding additional error cases is much greater than a change that would completely change the type of the error.
> > 
> > > > I see this functionality as a general limitation in the language. For example, errors are not the only context where you may want to return a type of A, B, or C. There have been other proposals on how we might do that in Swift. If and when it was solved in the general case for type parameters, I can’t foresee a compelling reason why it wouldn’t work in this context as well.
> > > 
> > > That makes sense in some ways, but I don’t think it’s unreasonable to ask for some analysis of whether a better design for typed errors would be possible if we had them. IMO it’s pretty important to get the design of typed errors right if / when we add them. If we don’t it will be considered a major mistake and will lead to a lot of less than desirable outcomes down the road.
> > > 
> > > I also think typed errors may be one of the more important use cases for structural sum types of some kind. If we are able to show that design problems that cannot be solved without them can be solved with them that might influence whether they are added or not. It might also influence when it makes sense to add support for typed errors to the language.
> > 
> > The problem can be solved without implicitly generated sum types though. The design of typed errors, as proposed, is to be consistent with the Swift type system today. Regardless, I’ve added a response in the “cirticisms” section that hopefully addresses this in some manner - basically, yes it would be helpful, but out of scope for this proposal.
> > 
> > > That approach would make catch clauses rather clunky by nesting errors inside of associated values. If you’re advocating for this approach do you have any ideas on how to streamline syntax for catching them?
> > 
> > See above example. Does that address this concern?
> > 
> > -David

---

<div class="post-metadata">

**Author:** ![owensd](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owensd/32/8934_2.png) [@owensd](https://forums.swift.org/u/owensd)\
**Post date:** [December 18, 2015, 5:34pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/18 "2015-12-18T17:34:56Z")

</div>

I’d be ok with having enum/struct only error types, however, I don’t have a compelling reason to really limit their usage context. Also, that would complicate the bridging with NSError at the moment.

FYI: I’ve added some updates to the criticism section to qualify the Java checked-exceptions and the multiple error type annotations.

-David

> **···**
>
> > On Dec 18, 2015, at 9:21 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:
> > 
> > Oh, I see what you mean. I considered polymorphic types to be class hierarchies, when you're talking about ErrorType polymorphism.
> > 
> > Yes, I think that the compiler should be aware of what the function can throw, but I would be happier if it stayed a bit inconvenient to use reference types.
> > 
> > > Le 18 déc. 2015 à 12:17:06, Félix Cloutier via swift-evolution \<swift-evolution@swift.org\> a écrit :
> > > 
> > > I'm not sure I understand your comment either. If I understand correctly, you say that the problem I describe is applicable only to polymorphic types (which is true). However, you then say that the only option today is polymorphic error types. Isn't that an issue? (Also, why is it the only option today?)
> > > 
> > > > Le 18 déc. 2015 à 11:58:44, David Owens II \<david@owensd.io\> a écrit :
> > > > 
> > > > > On Dec 18, 2015, at 7:03 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:
> > > > > 
> > > > > 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.
> > > > 
> > > > I don’t follow this. Declaring a type that is an enum or a struct absolutely guarantees that the function only returns a single type. If the type is a class-based error, then sure, there’s not guarantee.
> > > > 
> > > > However, the only option today is polymorphic error types.
> > > > 
> > > > -David
> > > 
> > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > swift-evolution mailing list  
> > > swift-evolution@swift.org  
> > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![owensd](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owensd/32/8934_2.png) [@owensd](https://forums.swift.org/u/owensd)\
**Post date:** [December 19, 2015, 1:05am UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/19 "2015-12-19T01:05:24Z")

</div>

> Hi David
> 
> I started reading your proposal and I have a couple of questions.
> 
> In the Enum Base ErrorType example you mentioned that it requires a "catch { }" clause. However the code is already covering the two possible Enum values (OffBy1 and MutatedValue). Why is the "catch { }" required? I typed that code into a playground and I did not get any errors. Are you saying that because the Enum type could add a value in the future?

Playgrounds are basically in an anonymous function that throws, so the problem doesn’t show up there at the top level. Copy this into your playground.

enum MyError: ErrorType {  
&nbsp;&nbsp;&nbsp;&nbsp;case OnlyOne  
}

func thrower() throws { throw MyError.OnlyOne }

func nolies() {  
&nbsp;&nbsp;&nbsp;&nbsp;do {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try thrower()  
&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;catch MyError.OnlyOne { print("handled") }  
&nbsp;&nbsp;&nbsp;&nbsp;// catch { print("compiler error until uncommented") }  
}

> Also, you proposed the catch clause to use error as the name of the constant holding the error. Wouldn't it be better to let the programmer decide the name rather than hard coding it to use error? For example:
> 
> catch e where e.value == 0 { print("0") }  
> catch e where e.value == 1 { print("1") }  
> catch { print("nothing") }

The “error” name is already specified in the Swift rules for what the constant is. I don’t see any compelling reason to propose a change to that.

-David

> **···**
>
> > On Dec 18, 2015, at 4:38 PM, Ricardo Parada \<rparada@mac.com\> wrote:

---

<div class="post-metadata">

**Author:** ![dennislysenko](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dennislysenko/32/41738_2.png) [@dennislysenko](https://forums.swift.org/u/dennislysenko)\
**Post date:** [December 18, 2015, 5:39pm UTC](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623/20 "2015-12-18T17:39:21Z")

</div>

It certainly would complicate NSError bridging, David. What you could do is  
treat it as a special case, so saying "throws NSError" in Swift would not  
be allowed, but the objC functions that take an inout NSError parameter are  
automatically annotated by "throws NSError" in Swift usage. This steps  
around almost any restriction on what we programmers can specify to be  
thrown in Swift.

> **···**
>
> On Fri, Dec 18, 2015 at 12:35 PM David Owens II via swift-evolution \< swift-evolution@swift.org\> wrote:
> 
> > I’d be ok with having enum/struct only error types, however, I don’t have  
> > a compelling reason to really limit their usage context. Also, that would  
> > complicate the bridging with NSError at the moment.
> > 
> > FYI: I’ve added some updates to the criticism section to qualify the Java  
> > checked-exceptions and the multiple error type annotations.
> > 
> > -David
> > 
> > \> On Dec 18, 2015, at 9:21 AM, Félix Cloutier \<felixcca@yahoo.ca\> wrote:  
> > \>  
> > \> Oh, I see what you mean. I considered polymorphic types to be class  
> > hierarchies, when you're talking about ErrorType polymorphism.  
> > \>  
> > \> Yes, I think that the compiler should be aware of what the function can  
> > throw, but I would be happier if it stayed a bit inconvenient to use  
> > reference types.  
> > \>  
> > \>\> Le 18 déc. 2015 à 12:17:06, Félix Cloutier via swift-evolution \< \> swift-evolution@swift.org\> a écrit :  
> > \>\>  
> > \>\> I'm not sure I understand your comment either. If I understand  
> > correctly, you say that the problem I describe is applicable only to  
> > polymorphic types (which is true). However, you then say that the only  
> > option today is polymorphic error types. Isn't that an issue? (Also, why is  
> > it the only option today?)  
> > \>\>  
> > \>\>\> Le 18 déc. 2015 à 11:58:44, David Owens II \<david@owensd.io\> a écrit :  
> > \>\>\>  
> > \>\>\>  
> > \>\>\>\> On Dec 18, 2015, at 7:03 AM, Félix Cloutier \<felixcca@yahoo.ca\> \> wrote:  
> > \>\>\>\>  
> > \>\>\>\> 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.  
> > \>\>\>  
> > \>\>\> I don’t follow this. Declaring a type that is an enum or a struct  
> > absolutely guarantees that the function only returns a single type. If the  
> > type is a class-based error, then sure, there’s not guarantee.  
> > \>\>\>  
> > \>\>\> However, the only option today is polymorphic error types.  
> > \>\>\>  
> > \>\>\> -David  
> > \>\>\>  
> > \>\>  
> > \>\> \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > \>\> swift-evolution mailing list  
> > \>\> swift-evolution@swift.org  
> > \>\> [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)  
> > \>
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

[Next page](https://forums.swift.org/t/proposal-allow-type-annotations-on-throws/623.md?page=2)
