Status check: Typed throws

I was concerned that would be the case, but was hopeful nonetheless. Doesn’t hurt to ask the question. Thank you for the erudite responses.

Many people are saying that API stability would be a problem, I think.

Let's say I have the following function in my library:

func getContents(ofURL urlString: String) async throws (NetworkError) -> Data {
    let url = URL(fromString: urlString)!
    return try await getData(url)
}

But now I decide that I want to throw a URLParsingError when the URL parsing fails. Since I already committed to the fact that getContents(ofURL:) only throws a NetworkError, I cannot just throw another error, so I have to change my function signature, which could be a source break for many clients of my library. Therefore I can only make this change in a new major version of my library. This dilemma could have been avoided, had I just used an untyped throws instead.


Although I can understand this argument against typed throws, I personally don't find it that compelling. Sure, some people can and will misuse typed throws, but most people won't, since we will leave untyped throws as the default. I can also see that it is actually nice, that I could actually notify the users of my library that there is a new error that might be thrown from a function which they might care about. With untyped errors, users often write catch-all clauses that aren't that helpful, because they either just crash or just print the unknown error.
Also, I think it's a bit odd that the thrown error is singled out as something that should not break sources when changed, while everything else about a function (argument types, return type, etc.) still does. What is the big difference?

Yeah, but it's already true - maybe later you decide it should return a String instead of Data, or a file handle, or whatever else. Or you decide it should really take an actual URL rather than a String.

This does raise a question, however, about overloading. I think we've all been assuming you can't overload a method based on its throw type(s). Although my instinct is to concur with that presumption, it's worth exploring.

If throws overloading isn't permitted, then that does become a meaningful distinction, as function parameters and return types can be overloaded in Swift (although the latter is apparently widely regarded as a mistake, due to its burden on type inference). Overloading is not a panacea but sometimes is a useful escape hatch for what would otherwise have to be an ABI-breaking change.

Yeah, that's an aspect of the counter-position that I'm still puzzled by. Is it that opponents are concerned as some kind of matter of principle - that they think nobody should have the functionality even if it doesn't effect them - or is it a concern that in practice there'll be some "viral" aspect which will coerce them into using typed throws when they don't want to? If the latter, I'd like to see that demonstrated a bit more clearly, as I don't see any reason why untyped catch clauses - i.e. } catch {, as are very common today - wouldn't continue to be universally acceptable (to the compiler) and effectively defend borders.

3 Likes

Hey all,

A quick update: I've kicked off a new pitch thread with a complete proposal.

Doug

11 Likes

Should we allow a comma list of error types rather than limit it to one type of error?

I’m going to close this thread now, further discussion should happen on the new pitch thread.

2 Likes