[swift-evolution] [Pitch] Typed throws

Matthew Johnson matthew at anandabits.com
Fri Feb 17 15:51:53 CST 2017


> On Feb 17, 2017, at 3:45 PM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
>> On Feb 17, 2017, at 11:03 AM, Adrian Zubarev via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> I suggest we need to find a way to shorten the list of the possible error types with a the help of typeallias
>> 
>> extension MyError1: Error { ... }
>> extension MyError2: Error { ... }
>> extension MyError3: Error { ... }
>> 
>> typealias MyErrors = MyError1 | MyError2 | MyError3  
>> 
>> func foo() throws(MyErrors) -> MyResult
>> func bar<T : Error>(_: () throws(T) -> Void) rethrows(MyErrors, T) -> MyResult
> Do you actually need that? Experience in other languages like Rust and Haskell that use Result-based error propagation suggests that a single error type is adequate, and beneficial in many ways. If nothing else, you could `Either` your way to multiple errors if you really needed to.
> 
> IMO, if we accept a single error type per function, there could be a simpler model for this. We could say that the `throws` type is a generic parameter of all function types, and it defaults to the uninhabited `Never` type for functions that don't throw.
> 
> () -> () == () throws Never -> ()
> () throws -> () == () throws Error -> ()
> 
> In this model, you'd get many benefits:
> 
> - `rethrows` could become first-class, reducing down to just polymorphic `throws`:
> 
> func foo(_: () throws -> ()) rethrows // Swift 3
> func foo<T: Error>(_: () throws T -> ()) throws T // Swift X
> func foo<T: Error>(_: () throws T -> ()) throws Either<MyErrors, T>
> 
> - Protocols could abstract over error handling; for instance, we could support throwing sequences:
> 
> protocol IteratorProtocol {
>   associatedtype Element
>   associatedtype Error: Swift.Error = Never
> 
>   mutating func next() throws Error -> Element?
> }
> 
> Separate of the type system model, the type *checking* model also deserves thorough consideration. Propagating the effects of possibly multiple error types propagating within a `do` block is much trickier than doing so as a single "throws" or not bit, especially if you want to be able to use type context in `catch` patterns or to implicitly propagate a narrower `throws` type out of the enclosing function.

I agree with all of this. The correct way to handle functions that throw multiple error types is with a discriminated union (enum) or an existential.  

If we make enums easier to work with (see my manifesto on generalized enums and value subtyping), we also make it easier to address the use case of functions that need to throw several different error types.  That is the more general and useful way to address this use case.

> 
> -Joe
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170217/76208e9c/attachment.html>


More information about the swift-evolution mailing list