Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Many modern languages provide rich exception handling features, but Apple's Swift programming language does not provide an exception handling mechanism.

Steeped in exceptions as I am, I'm having trouble wrapping my mind around what this means. Swift has assertions, and of course return values; but I'm having trouble picturing how my exception-based way of thinking maps to a world without exceptions (and, for that matter, why such a world is desirable). Are there things I can't do in a language like Swift that I could do with exceptions? Do I gain something by losing exceptions?

How for example might I best express something like

try:
    operation_that_can_throw_ioerror()
except IOError:
    handle_the_exception_somehow()
else:
     # we don't want to catch the IOError if it's raised
    another_operation_that_can_throw_ioerror()
finally:
    something_we_always_need_to_do()

in a language (Swift, for example) that lacks exception handling?

share|improve this question
4  
You may want to add Go to the list, if we just ignore panic which is not quite the same. In addition what is said there, an exception is not much more than a sophisticated (but comfortable) way to perform a GOTO, although nobody calls it that way, for obvious reasons. –  JensG Oct 3 at 18:51
2  
The sort answer to your question is that you need language support for exceptions in order to write them. Language support generally includes memory management; since an exception can be thrown anywhere and caught anywhere, there needs to be a way to dispose of objects that doesn't rely on the control flow. –  Robert Harvey Oct 3 at 19:07
6  
This is not "opinion based." There are concrete reasons behind it. –  Karl Bielefeldt Oct 3 at 19:57
2  
Even if you can't answer, "Why did this specific design group make this specific decision," you can answer, "Why would a modern language designer want to omit exceptions," which is really what he wants to know. I suppose it could be edited to be somewhat more generic, but then you guys would complain about not providing a specific example. –  Karl Bielefeldt Oct 3 at 21:04
2  
His original title was actually pretty good. I restored it and did a bit of editing to make it a little more clear that he was using Swift as an illustrative example, but I think you really have to read between the lines to see otherwise. –  Karl Bielefeldt Oct 3 at 22:02

4 Answers 4

up vote 7 down vote accepted

In embedded programming, exceptions were traditionally not allowed, because the overhead of the stack unwinding you have to do was deemed an unacceptable variability when trying to maintain real-time performance. While smartphones could technically be considered real time platforms, they are powerful enough now where the old limitations of embedded systems don't really apply anymore. I just bring it up for the sake of thoroughness.

Exceptions are often supported in functional programming languages, but so rarely used that they may as well not be. One reason is lazy evaluation, which is done occasionally even in languages that are not lazy by default. Having a function that executes with a different stack than the place it was queued to execute makes it difficult to determine where to put your exception handler.

The other reason is first class functions allow for constructs like options and futures that give you the syntactic benefits of exceptions with more flexibility. In other words, the rest of the language is expressive enough that exceptions don't buy you anything.

I'm not familiar with Swift, but the little I've read about its error handling suggests they intended for error handling to follow more functional-style patterns. I've seen code examples with success and failure blocks that look very much like futures.

Here's an example using a Future from this Scala tutorial:

val f: Future[List[String]] = future {
  session.getRecentPosts
}
f onFailure {
  case t => println("An error has occured: " + t.getMessage)
}
f onSuccess {
  case posts => for (post <- posts) println(post)
}

You can see it has roughly the same structure as your example using exceptions. The future block is like a try. The onFailure block is like an exception handler. In Scala, as in most functional languages, Future is implemented completely using the language itself. It doesn't require any special syntax like exceptions do. That means you can define your own similar constructs. Maybe add a timeout block, for example, or logging functionality.

Additionally, you can pass the future around, return it from the function, store it in a data structure, or whatever. It's a first-class value. You're not limited like exceptions which must be propagated straight up the stack.

Options solve the error handling problem in a slightly different way, which works better for some use cases. You're not stuck with just the one method.

Those are the sorts of things you "gain by losing exceptions."

share|improve this answer
    
So Future is essentially a way of examining the value returned from a function, without stopping to wait for it. Like Swift, it's return-value based, but unlike Swift, the response to the return value can occur at a later time (a bit like exceptions). Right? –  raxacoricofallapatorius Oct 4 at 20:52
    
You understand a Future correctly, but I think you might be mischaracterizing Swift. See the first part of this stackoverflow answer, for example. –  Karl Bielefeldt Oct 4 at 20:57
    
Hmm, I'm new to Swift, so that answer is a bit hard for me to parse. But if I'm not mistaken: that essentially passes a handler that can be invoked at a later time; right? –  raxacoricofallapatorius Oct 4 at 21:09
    
Yes. You're basically creating a callback when an error occurs. –  Karl Bielefeldt Oct 4 at 21:14

Exceptions can make code more difficult to reason. While they aren't quite as powerful as gotos, they can cause many of the same problems due to their non-local nature. For example, let's say you have a piece of imperative code like this:

cleanMug();
brewCoffee();
pourCoffee();
drinkCoffee();

You can't tell at a glance whether any of these procedures can throw an exception. You have to read the documentation of each of these procedures to figure that out. (Some languages make this slightly easier by augmenting the type signature with this information.) The above code will compile just fine regardless of whether any of the procedures throw, making it really easy to forget to handle an exception.

Additionally, even if the intent is to propagate the exception back to the caller, one often needs to add additional code to prevent things from being left in an inconsistent state (e.g. if your coffeemaker breaks, you still need to clean up the mess and return the mug!). Thus, in many cases code that uses exceptions would look just as complex as as code that didn't because of the extra cleanup required.

Exceptions can be emulated with a sufficiently powerful type system. Many of the languages that avoid exceptions use return values to get the same behavior. It's similar to how it's done in C, but modern type systems usually make it more elegant and also harder to forget to handle the error condition. They may also provide syntactic sugar to make things less cumbersome, sometimes almost as clean as it would be with exceptions.

In particular, by embedding error handling into the type system rather than implementing as a separate feature allows "exceptions" to be used for other things that aren't even related to errors. (It's well known that exception handling are actually a property of monads.)

share|improve this answer
    
Is it correct that kind of type system that Swift has, including optionals, is the sort of "powerful type system" that achieves this? –  raxacoricofallapatorius Oct 4 at 12:45
1  
Yes, optionals and, more generally, sum types (referred to as "enum" in Swift/Rust) can achieve this. It takes some extra work to make them pleasant to use, however: in Swift, this is achieved with the optional chaining syntax; in Haskell, this is achieved with monadic do-notation. –  Rufflewind Oct 4 at 17:32

One thing I was initially surprised about the Rust language is that it doesn't support catch exceptions. You can throw exceptions, but only the runtime can catch them when a task (think thread, but not always a separate OS thread) dies; if you start a task yourself, then you can ask whether it exited normally or whether it fail!()ed.

As such it is not idiomatic to fail very often. The few cases where it does happen are, for example, in the test harness (which doesn't know what the user code is like), as the top-level of a compiler (most compilers fork instead), or when invoking a callback on user input.

Instead, the common idiom is to use the Result template to explicitly pass up errors that should be handled. This is made significantly easier by the try! macro, which is can be wrapped around any expression that yields a Result and yields the successful arm if there is one, or otherwise returns early from the function.

use std::io::IoResult;
use std::io::File;

fn load_file(name: &Path) -> IoResult<String>
{
    let mut file = try!(File::open(name));
    let s = try!(file.read_to_string());
    return Ok(s);
}

fn main()
{
    print!("{}", load_file(&Path::new("/tmp/hello")).unwrap());
}
share|improve this answer
    
So is it fair to say that this too (like Go's approach) is similar to Swift, which has assert, but no catch? –  raxacoricofallapatorius Oct 4 at 12:43
 int result;
 if((result = operation_that_can_throw_ioerror()) == IOError)
 {
  handle_the_exception_somehow();
 }
 else
 {
   # we don't want to catch the IOError if it's raised
   result = another_operation_that_can_throw_ioerror();
 }
 result |= something_we_always_need_to_do();
 return result;

In C you would end up with something like the above.

Are there things I can't do in Swift that I could do with exceptions?

No, there isn't anything. You just end up handling result codes instead of exceptions.
Exceptions allow you to reorganize your code so that error handling is separate from your happy path code, but that is about it.

share|improve this answer
    
And, likewise, those calls to ...throw_ioerror() return errors rather than throwing exceptions? –  raxacoricofallapatorius Oct 3 at 19:37
    
@raxacoricofallapatorius If we are claiming exceptions don't exist then I assume the program follows the usual pattern of returning error codes on failure and 0 on success. –  stonemetal Oct 3 at 19:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.