Why doesn't Swift have explicit throwables like Java

I can't understand why Swift doesn't explicit indicates which types of exceptions a function can throw, like Java does.

Java example:

static void fun() throws MyException { 
    // ...
    throw new MyException(123,"abc") 
}

When I'm using this function, I know exactly what kind of exceptions it can throw. The editor can even help me construct an exhaustive handling of exceptions.

In Swift we tend to use enums, but we don't know what kind of enum or enums can a function throw.

Am I doing something wrong here? I know that adding documentation helps, but not even Apple adds documentation for throws.

1 Like

Correct, Swift errors are not typed. I believe there had been talk about a future version of swift allowing for the specificion of what errors a function could throw.

The feature you're referring to has been discussed here under the named of typed throws. You can learn about the pros and cons of such a design by using the search function of these forums (just search for "typed throws") to review the very extensive discussions.

4 Likes

Professionally, I program in Java for a big 4 company. Typed exceptions are the death of me.

When your codebase gets big enough, your functions end up having many callers. Any time you wish to throw a new class of exception, you will encounter 1 of 4 scenarios:

  1. You don't have many callers. You add the new exception type in the declaration, and you refactor your call sites accordingly. This is the happy case, woohoo!
  2. You have many callers. It's a nuisance, but you can still refactor them all.
  3. Many of the call sites are from other teams' code. You have to bug them to write a patch to deal with your API breaking change. To warrant this, you better have a really good reason to do this.
  4. You don't even know who your consumers are. It's almost impossible to release an API breaking change like this.

For example, I was fixing a bug in a method that accidentally percent-encoded some file paths, because it was using URL. I refactored the code to use URI, but that throws a URISyntaxException that I couldn't meaningfully handle. The method already declared that it can throw FileNotFoundException, but type is with incompatible with URISyntaxException. There were at least 180 call sites that had to be updated to handle this exception. The only feasible solution was to:

...
catch (URISyntaxException uriE) {
   throw new RuntimeException(uriE) // Father forgive me, for I have sinned.
}
7 Likes

Thank you, I've tried to search in swift-evolution repo and here, but couldn't find anything.

There was a discussion on the 'Evolution' forum, but it looks like it has stopped as Feb '17:

Click on the magnifying glass in the top right corner and write "typed throws" without the quotation marks. You will find many discussions dating back several years:

[Discussion] Analysis of the design of typed throws

Evolution Discussion

Feb '17 - # Analysis of the design of typed throws ## Problem There is a problem with how the proposal specifies rethrows for functions that take more than one throwing function. The proposal...

[Pitch] Typed throws

Evolution Pitches

Feb '17 - Now this is on-topic, I guess. Last time we stopped at John McCall’s syntax: extension MyError: Error { ... } func foo() throws(MyError) - > MyResult It’s conservative and prevents visual ambiguity with extra parentheses. If we (somewhat) agree on this, then submitting a proposal will be trivial. ​

typed throws

Evolution Discussion

Aug '17 - Splitting this off into its own thread: One related topic that isn’t discussed is type errors. Many third party libraries use a Result type with typed errors. Moving to an async / await model without also introducing typed errors into Swift would require giving up something that is highly valued by...

[Proposal] Typed throws

Evolution Discussion

Feb '17 - I’ve created a proposal draft, copy-pasting some parts from David Owens’ proposal. Here it is < Draft of "Typed throws" proposal · GitHub Draft of "Typed throws" proposal · GitHub > . I had to make one addition, which hasn’t been discussed yet. Look at ...

Is it possible to specify error type thrown in a protocol method

Using Swift

Jul '17 - Hi Swifters, I am wondering if it is possible to specify error types thrown in a protocol method. By allowing us to do it and letting the compiler check all the implementations of the protocol to make sure only they would only throw the specified error types, we only need to catch our error types...

Proposal: Typed throws

Evolution Discussion

Dec '15 - IMHO be careful what you wish for. If the compiler enforces this then we're just repeating the mistakes of Java's checked exceptions. All roads would eventually lead to "throws ErrorType", defeating the supposed purpose. russ

Proposal: Typed throws

Evolution Discussion

Dec '15 - ...ke a billion times already, but I'd like to be official and make a proper proposal for that. So having said that, I hereby propose adding support for typed throws annotations. If a function can throw, it is often known what type of error it may throw. Consider this piece of code: enum NetworkError: Err...

Proposal: Allow Type Annotations on Throws

Evolution Discussion

Dec '15 - 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...

Type-annotated throws

Evolution Discussion

Aug '16 - Hi all, Currently, a function that throws is assumed to throw anything. There was a proposal draft last December to restrict that. The general idea was that you'd write, for instance: enum Foo: ErrorProtocol { case bar case baz } func frob() throws Foo { throw Foo.bar // throw .bar? } If you `cat...

Proposal: Allow Type Annotations on Throws

Evolution Discussion

Jan '16 - ...g/pipermail/swift-evolution/Week-of-Mon-20151214/003284.html [swift-evolution] Proposal: Allow Type Annotations on Throws > on "typedthrows". First of all, I just love the improvement from the caller point of view. The following: func updateData() throws DataUpdateError - > Data do...

[PITCH] Add Ability To Specify Error Type On Throws

Evolution Pitches

Aug '16 - Hello, Consider the scenario of the vending machine example in the Swift Book: We have a function that throws errors from a single given ErrorType 1. func vend(itemNamed name: String) throws { 2. guard let item = inventory[name] else { 3. throw VendingMachineError.InvalidSelection 4. } 5. 6. guar...

Add ability to specify the error type on throws

Evolution Discussion

Aug '16 - Hello, Consider the scenario of the vending machine example in the Swift Book: We have a function that throws errors from a single given ErrorType 1. func vend(itemNamed name: String) throws { 2. guard let item = inventory[name] else { 3. throw VendingMachineError.InvalidSelection 4. } 5. 6. guar...

Sorry for my lack of clarity, I did that, but the most recent/relevant was from February 2017.

You don't need to restrict your reading to only the most recent thread; there are insightful comments in discussions from 2015 and 2016 about the topic as well.

5 Likes

Hey, you can always go back to (what I call) the savagery, for example, in Java:

static void fun() throws Exception { 
    // ...
    throw new MyException(123,"abc");
    throw new YourException(456,"xyz");
}

What we are trying to avoid here is this:

Why are you doing that?

You know that Error already has var localizedDescription: String { get } in the protocol? You should override that, and use print(error.localizedDescription), that's the way you ensure that every error is covered, even when the error comes from other libraries. And it even works when you haven't overridden the localizedDescription.

No, Error is from Swift's standard library, like struct String, func print and protocol CustomStringConvertible.

It's because developers who speak other languages than English have developed the habit of displaying localized error messages. And they have learned the hard way that life is much easier when this concern is embedded in a user-facing project right from the start :slight_smile: