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

David Owens II david at owensd.io
Fri Dec 18 12:36:17 CST 2015


> On Dec 18, 2015, at 9:41 AM, Matthew Johnson <matthew at 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>.

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>>
         (file_path: &Option<P>, city: &str)
         -> Result<Vec<PopulationCount>, CliError> {
    ...
}
It’s the CliError which is defined as:
enum CliError {
    Io(io::Error),
    Csv(csv::Error),
    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 {
    case IO(String)
    case Number(Int)
}

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

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

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


More information about the swift-evolution mailing list