Error Handling in Swift

Update, August 22nd, 2014: Please seeError Handling – Take Two for some updated insights. It may be the case that named tuples are the right approach to solve this problem.

: .info

Error handling is something that seems to be have been left to the coder to figure out for Swift. Yes, there is the overly clunky and terribly awkwardNSError usage:

func contentsForType(typeName: String,                        error: NSErrorPointer) -> AnyObject!{    // some code, oops! an error    if error {        error.memory = NSError(domain: domain,                                 code: code,                             userInfo: [:])    }    return nil}

That is terrible. Not only do we need to use theNSError class and jump over into the ObjC runtime, for absolutely no good reason, we get to use a terrible syntax that is not how Swift even wants you to work. At the very least error could be aninout reference and we can do something nicer…

Well, I think we can do better: we can borrow from other languages! Haskell has a concept of anEither type that is essentially "either this value or that". That's pretty much want we want: "either our return value or an error". Great! Let's implement that and see how it feels in Swift.

Let's start out with some requirements:

  1. Need to support error information for function calls that have no return value
  2. Need to support error information for function calls that return a value
  3. Pure Swift implementation
  4. Names that clearly identify what we are working with

With those requirements, we know that we are going to need three different items:

  1. Error —  a type that represents the error information. This will simply be modelled after theNSError type

2Failable  —  a type that represents either the error state or a success state with no return value

  1. FailableOf<T> —  a type that represents either the error state or a success state with a return value

TheError class is the easiest and most straight-forward:

struct Error {  typealias ErrorInfoDictionary = Dictionary<String, Any>  let code: Int  let domain: String  let userInfo: ErrorInfoDictionary  init(code: Int, domain: String, userInfo: ErrorInfoDictionary?) {    self.code = code    self.domain = domain    if let info = userInfo {      self.userInfo = info    }    else {      self.userInfo = [String:Any]()    }  }}

There really is not much to say about the class: it is basically the Swift version of theNSError class from ObjC.

Now, to tackle theFailable type:

enum Failable {  case Success  case Failure(Error)  init() {    self = .Success  }  init(_ error: Error) {    self = .Failure(error)  }  var failed: Bool {    switch self {    case .Failure(let error):      return true    default:      return false    }  }  var error: Error? {    switch self {    case .Failure(let error):      return error    default:      return nil    }  }}

An enum is the perfect choice for us because aFailable has exactly two states:Success andFailure. There are no other possibilites.

On top of that, we have some helper methods failed and error that prevent us from having to write this terrible code to get the values out each time:

switch result {case .Failure(let error):  // handle the error heredefault: // no error, do something else}

Instead, we can write much more natural code:

let result = failableMethod()if result.failed {  // handle the error}// continue on

I'm going to pause here. Some of you may be wondering, why not implement theLogicValue protocol? Great question! Because that protocol is the DEVIL!

if result { // handle the error?? or does this mean there is a result???}// continue on?

I find the protocol extremely ambiguous and error prone. That's why I'm not using it.

TheFailableOf<T> is not that much different, other than a fairly annoying bug in Swift that cannot generate the correct code—more on that in a minute.

enum FailableOf<T> {  case Success(FailableValueWrapper<T>)  case Failure(Error)  init(_ value: T) {    self = .Success(FailableValueWrapper(value))  }  init(_ error: Error) {    self = .Failure(error)  }  var failed: Bool { /* same as above … */ }  var error: Error? { /* same as above … */ }  var value: T? {    switch self {    case .Success(let wrapper):      return wrapper.value    default:      return nil    }  }}

There are a few changes:

  1. A value is stored for the Success state
  2. A new value property has been added
  3. There is this peskyFailableValueWrapper

There is a bug in Swift where the compiler cannot generate the code for an enum that does not have a fixed layout, which would be the case if theSuccess value could hold any old type ofT. To get around this, we can create a wrapper class so that theFailableOf<T> can essentially use the class pointer size for laying about the enum. Hopefully this gets addressed in later drops.

That's basically it. Now we can handle errors in a much more Swift-friendly way. Below is some sample use case:

func failWhenNilAndReturn(name: String?) -> FailableOf<T> {  // not using .Success because of the  // FailableValueWrapper workaround.  if let n = name { return FailabeOf<T>(n) }  else { return .Failure(Error(code: 2,                              domain: "err",                            userInfo: nil)) }}let result = failWhenNilAndReturn("David")if result.failed { /* handle the error */ }println("name: \(result.value!)")

I'm not the first to write on this topic, nor will I be the last. This is definitely an odd area that was left out for Swift…

The full source code can be found in my SwiftLib project on GitHub:https://github.com/owensd/SwiftLib.

Error Handling in Swift