There were some big changes to Swift this week. The most surprisingly controversial one was the adding of “exceptions.” I put those in quotes because they are quite unlike traditional exceptions in C++, C#, Java or Python even though I’ve called them Pythonesque at times.1 Whoa. People on both sides of the debate flip out on that!
There have been two types of reactions.
First (the majority) is excitement. Finally we have something to avoid all those nested and hard to read if statements.
Second (a loud minority) are those groups that hate exceptions or think Swift did them wrong. From what I can tell one group are primarily those coming from ObjcC where exceptions were always warned against. (ObjC has long had C++ styled exceptions but few use them) There’s also the Haskell/Clojure folks who also hate exceptions. Both these groups shout the, “Swift isn’t learning from the mistakes of the past and is dominated by C++ folks.” The related group (sometimes also disliking exceptions in general but sometimes a fan of C++ or related exceptions) are those who note that Swift’s exceptions aren’t even really exceptions.
When I raise the “real exceptions” some other people flip out. So just to be clear here are the ways Swift exceptions aren’t like “real” exceptions in C++.
1. They don’t bubble up. In traditional languages if you don’t deal with an exception the function that calls you can. In Swift if you deal with a throw you have to deal with it and all possibilities. This means you have to put catch clauses for every error returning function making them more complicated to write. This whole concern is often cast as the difference between unwinding the call stack versus what is really just syntactical sugar replacing a bunch of if statements. Thus the bubble up complaint is often tied to the complexity complaint even if in practice I don’t think most people will be handling that many cases. (Edit: just to be clear – you have to either handle the error or declare it to be thrown. It’s automatic bubbling up that doesn’t happen)
2. Most problems don’t throw exceptions. Unlike most languages going past array boundaries doesn’t throw an exception. Neither does division by zero. It’s possible those sorts of things may get added to the language down the line. You can add this functionality to the base collections if you want. But unlike say Python it doesn’t come out of the box.
The problem is actually a little deeper than this. Swift could always throw ObjC exceptions via NSException. However it never could respond to traditional exceptions like a problem with a file class. Unless the Swift developers have added more magic than I’m aware of, you still can’t respond to these types of problems. So unexpectedly invalidated file handles or terminated socket connections aren’t caught. Of course most ObjC programmers didn’t catch exceptions from file handling anyways. So it’s not like this is a huge shift. However if Swift is supposed to be a language capable of systems programming (this line of reasoning goes) it really has to be able to respond to these sorts of exceptions. Further Swift should be unifying error handling not making things more complicated.
A key common feature of these complaints are that Swift’s exceptions really aren’t for handling crashes (as with C++ or even ObjC exceptions) but are for handling errors.
3. Swift Exceptions can’t handle asynchronous code. C# exceptions apparently can go between threads if you do the right things.2 To be fair, especially compared to languages like Go, Swift just doesn’t do threading well at all. At best you can use existing Cocoa features to handle the cases you’d normally have threads. Things like Grand Dispatch Station. But it’s really not as good as notifications as a general part of error handling or “exceptions.”
4. You have to label functions that use throw. I’m not quite sure why this is beyond clarifying for the caller that they have to handle exceptions and perhaps to allow easier compiler optimizations. Syntactically this is a big difference from the types of exceptions most are used to. As I said this is related to the bubbling up problem.
5. The terminology is bad for an error throwing mechanism versus exceptions. I’ve heard this one a lot from all sides. Even some on the pro-Swift “exception” side get pedantic and say it’s properly “Swift error handling.” The controversy here is that by calling them exceptions people get the wrong idea about what they can do. And, going the other way, programmers should be able to handle them being called something else despite looking like exceptions.
6. It doesn’t fix Cocoa’s error handling model. This one is where the ObjC traditionalists and those coming from other languages fight. Often (but not always) both sides hate exceptions. However Cocoa developers typically love (or are at least used to) NSError. Others say that Swift should have learned from what other recent languages have done for error handling. The problem, of course, is that most of those using Swift are using it to code Cocoa. So having to deal with the existing error handling of Cocoa probably was a smart design decision. This doesn’t end the criticism though since it then becomes, “Swift is too beholden to compatibility with Cocoa and it undermines the language.” Tied to all this are criticisms that the ErrorType protocol isn’t defined enough to do the things it ought.
As I said, I’ve been surprised how many discussions have been going on like this. I’ll not link to all of them. One interesting Twitter thread from a more Haskell perspective was this one by Justin Spahr-Summers. It’s long, but worth reading for some of the discussion. See also this ADN discussion which inspired some of the above. (There were also ARS discussions and several others I was following.)
My own view is that people are perhaps taking things too seriously. Swift is a very pragmatic language and it’s developing with a set of practical concerns. Mainly the connection to ObjC based Cocoa libraries. Maybe that’s undermining what the language could be. But especially for the next years, the primary purpose of Swift will be to code against Cocoa. For all the problems and limits of Swift exceptions, they do seem a big step up from difficult to read nested if statements. Maybe this decision will limit Swift in the future. But in the present it’ll make most people’s life easier.
Someone once said, “the perfect is the enemy of the good.” That probably applies to Swift with regards to the practical problems people are using it on.
- I think I called them Pythonesque because it’s fairly common in Python to use exceptions for error handling and not just unexpected catastrophic failures. To be fair not everyone agrees with that type of programming. Also unlike C++ Python’s exceptions are kind of intrinsically tied to an error state and the error state isn’t necessary catastrophic. The calling function is just supposed to respond to the error, fix things up a bit so you can continue and clear the error indicator. (See Python exceptions) ↩
- I don’t code C# but this is what I’ve been told. Although apparently you have to use Task<T> instead of a normal thread creation. ↩
- 77Nick Lockwood has one of the best discussions of Swift exceptions I’ve found both in terms of design, problems and benefits.
- 63“Silver” brings Apple’s Swift language to the .NET and Java worlds. It brings the language not the Cocoa libraries though. Sounds like they added exceptions to let Swift work with .NET or Java better. (Personally I think Apple should add exceptions too, but I know people at Apple really don’t like…
- 54Could have sworn I’d linked to this before. But I guess not. It’s well worth reading. Reactive Cocoa in Swift. The biggest issue right now is that Swift can’t see macros in ObjC/C. Given some of the problems that introduces I’ll hold off until things get more mature. The linked…