Error Handling in Swift

Update, August 22nd, 2014: Please see Error 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 awkward NSError 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 the NSError 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 an inout 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 an Either 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 the NSError type

2 Failable  —  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

The Error 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 the NSError class from ObjC.

Now, to tackle the Failable 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 a Failable has exactly two states: Success and Failure. 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 here

default:
 // 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 the LogicValue 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.

The FailableOf<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 pesky FailableValueWrapper

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 the Success value could hold any old type of T. To get around this, we can create a wrapper class so that the FailableOf<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