Implementing printing versions of “try?” and “try!” — on steroids! in #swiftlang

Swift 2’s try? operator bridges optionals and error handling by converting thrown errors into nil results. With it, you can use guard statements and conditional binding to focus development solely on success cases.

guard let foo = try? somethingThatMayThrow else {
    handle error condition without specific details
    and leave scope}

You lose any returned error information with this approach. The tl;dr version of the rest of this post is this: Discarding error information is kind of sucky. Why not automagically build in context and error printing with alternatives to try? and try!.

A while back, I shared a basic way to emulate try? without discarding those errors entirely. The following implementation first prints returned errors and then continues to return the result/nil return type that try? normally gets you:

func attempt<T>(block: () throws -> T) -> Optional<T>{ 
    do { return try block() } 
    catch { print(error); return nil } 
}

This works great when returned values play some further role but what do you do when you want to use guard statements with failable procedures that don’t return meaningful values, while retaining attempt‘s error-printing behavior. For example, consider many of NSFileManager’s file creation and deletion utilities.

NSFileManager.defaultManager().removeItemAtURL(someURL)

Your choices are this: wrap in a do-catch block (wordy), use attempt with try? and then try to wrangle the returned nil value, or use try! and lose all the error information.

There’s of course, another way. In the gist you find at the end of this post, I’ve built attemptFailable. It wraps throwing statements in minimal printing guard/try system that returns Boolean values. Here’s how that looks in use:

if NSFileManager.defaultManager().fileExistsAtPath(myPath) {
    guard (attemptFailable{try NSFileManager.defaultManager()
         .removeItemAtURL(myURL)}) else {abort()}
}

Not ideal, obviously, but pretty handy when writing utilities in playgrounds, which I do more and more these days. (Playgrounds are  awesome. Buy my book.)

You can enhance try! in a similar fashion. The doOrDie function in this gist creates more informative versions for try-and-die than the Swift-supplied option. Like attempt and attemptFailable, it captures context and thrown errors and print both before continuing with standard try! execution termination.

Here’s the code.

2 Comments