Nil vs throws #swiftlang

It is tempting to use optionals to signal when an operation has failed. The following snippet represents Swift prior to 2.0 and is common to Apple’s traditional Cocoa patterns. An unsuccessful operation returns nil, a successful one returns a value.

func doSomething() -> String? {
   let success = (arc4random_uniform(2) == 1) // flip a coin
   if success {return "success"} // succeed
   return nil // fail

if let result = doSomething() {
   // use result here

Starting in Swift 2.0, reserve this approach for initialization and prefer guard over if-let. Instead of using optionals as semaphores, that is to indicate success and fail conditions, use Swift’s new error handling system.

func betterDoSomething() throws -> String {
   let success = (arc4random_uniform(2) == 1) // flip a coin
   if success {return "success"} // succeed
   throw Error.failure // fail

do {
   let result = try betterDoSomething()
} catch {print(error)}

This refactoring skips optionals; the nil-case is never of interest to the client code. Swift 2.0 error-handling means you never have to unwrap.

This one change profoundly affects Cocoa-sourced APIs. Calls that used NSError pointers pre-Swift 2.0 change their return type from optional to non-optional, add the throws keyword, and eliminate error pointers from API calls. The new system works sends NSError through do-try-catch.

// Old
func dataFromRange(range: NSRange,
   documentAttributes dict: [NSObject : AnyObject],
   error: NSErrorPointer) -> NSData?

// New
func dataFromRange(range: NSRange,
   documentAttributes dict: [String : AnyObject]) throws -> NSData

By introducing error handling, optionals can eliminate their overloaded “failed call” semantics. It’s always better to use throws with well-defined errors than to use optional semaphores. When you really have no information to pass back to the caller other than “I failed”, Swift 2.0’s updated error system simplifies creating an error enumeration to explain why that failure occurred. It is ridiculously easy to add informative errors that don’t require complicated NSError initializers to construct.

enum Error: ErrorType {case BadData, MemoryGlitch, ItIsFriday}

Although many current APIs, especially those based on Core Foundation calls, have yet to transition to the new system, I encourage you to update your code to avoid using optionals as semaphores. Return your optionals to the “contains a value or does not contain a value” semantics they were designed to handle.

I’m working on the Swift Developer’s Cookbook for Pearson/Addison Wesley. Send me your questions and thanks for buying my books!


  • I totally get your rationale for taking a “throws” approach and I tried it extensively in my own code. However, it didn’t stick because it made my code ugly and I eventually reverted to using optional return values. Wherever I had been using “if let” (which I found very succinct and convenient) I was now forced to use “do … catch” (which seemed cumbersome and heavyweight.) I think that the deciding factor should be whether or not a method invocation can fail for multiple different reasons and whether your program can respond in kind. In those cases, as you suggest, use error enums and throws. If there’s only one reason for failure, or only one possible way to recover from it, my own experience (and code style) has taught that it’s simpler to use optionals. This approach also has the benefit of succinct optional chaining.

  • […] great post by Erica Sadun on this subject, Nil vs […]