Skip to content

Instantly share code, notes, and snippets.

@BlameOmar
Last active August 16, 2016 10:42

Revisions

  1. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -92,9 +92,9 @@ findAnswerToTheUltimateQuestion { result in
    dispatch_async(dispatch_get_main_queue()) {
    print(answer);
    }
    } catch let e {
    } catch let error {
    dispatch_async(dispatch_get_main_queue()) {
    print(e);
    print(error);
    }
    }
    }
  2. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 6 additions and 2 deletions.
    8 changes: 6 additions & 2 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -89,9 +89,13 @@ Here's how this function might be used:
    findAnswerToTheUltimateQuestion { result in
    do {
    let answer = try result.unwrap()
    //Do something with the answer
    dispatch_async(dispatch_get_main_queue()) {
    print(answer);
    }
    } catch let e {
    print(e)
    dispatch_async(dispatch_get_main_queue()) {
    print(e);
    }
    }
    }
    ```
  3. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,10 @@ Here's an example of how an asynchronous library function might be implemented:
    ```swift
    func findAnswerToTheUltimateQuestion(completion: (Result<Int>) -> ()) {
    //Computers are much faster today than they were in 1978, so this only takes a week
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1000*1000*1000*60*60*24*7), dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
    let latency: Int64 = 1000*1000*1000*60*60*24*7;
    let time = dispatch_time(DISPATCH_TIME_NOW, latency);

    dispatch_after(time, dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
    let result = Result {
    //any number of statements that may potentially throw
    return 42;
  4. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 18 additions and 8 deletions.
    26 changes: 18 additions & 8 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -11,13 +11,15 @@ Swift 2.0 introduces throwable errors, which are similar to exceptions. However
    propogate only down the call stack and can only be caught in the same thread that threw them. In order to propogate
    the errors upwards (such as to callback routines) and across thread boundaries it is necessary to catch the errors
    and pass them along in some sort of instantiable type, and however this is done, it is preferable to be able to
    later handle those errors the same way as all other thrown errors. One way to do this is through a thowing closure
    that either returns a value or thows an error, as detailed in
    [this blog post](http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/).
    However, this strikes me as odd as a closure can do anything and the desired behavior is very well defined. Through
    a simple extension to the familiar Result enum can serve this purpose.
    later handle those errors the same way as all other thrown errors.

    First we start with the familiar Result type:
    One way to do this is through a thowing closure that either returns a value or thows an error, as detailed in
    [this blog post](http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/). However, this strikes me
    as odd as a closure can do anything and the desired behavior is very well defined.

    Through a simple extension to the familiar Result enum can serve this purpose.

    First here is the definition of a typical Result enum:

    ```swift
    enum Result<T: Any> {
    @@ -26,7 +28,11 @@ enum Result<T: Any> {
    }
    ```

    Next, we add a simple extension:
    Many versions of the Result enum use NSError for the failure case, or accept a second type parameter for the
    failure case. ErrorType is a new protocol introduced in Swift 2.0 that all throwable errors, including NSError
    conform to.

    Here is the extension to Result:

    ```swift
    extension Result {
    @@ -54,7 +60,7 @@ The unwrap method returns the value for ```swift .Success``` and throws the erro
    The initializer provides a convenient way to create a Result object for an arbitary block of code, simplifying
    the implementation of asynchronous functions.

    Example:
    Here's an example of how an asynchronous library function might be implemented:

    ```swift
    func findAnswerToTheUltimateQuestion(completion: (Result<Int>) -> ()) {
    @@ -70,7 +76,11 @@ func findAnswerToTheUltimateQuestion(completion: (Result<Int>) -> ()) {
    }
    ```

    Thanks to type inference, there is no need to specify the type for the success case. If it weren't for syntax
    coloring and the capitalization of the R, it may not be apparent at a glance that Result isn't simply a
    language level construct.

    Here's how this function might be used:

    ```swift
    findAnswerToTheUltimateQuestion { result in
  5. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ As Swift 1.0 did not include support for exceptions, a common error handling pat
    that either took on a value on success, or an error on failure. In a way, this was superior to using exceptions,
    since being a instantiable type, Results could be passed around freely, enabling asynchronous code to use the same
    error handling mechanisim as synchronous code. Using Swift's robust support for custom operators, this also enabled
    [http://fsharpforfunandprofit.com/posts/recipe-part2/](Railway Oriented Programming) for more functional oriented
    [Railway Oriented Programming](http://fsharpforfunandprofit.com/posts/recipe-part2/) for more functional oriented
    programers.

    Swift 2.0 introduces throwable errors, which are similar to exceptions. However, like exceptions, thrown errors
    @@ -13,7 +13,7 @@ the errors upwards (such as to callback routines) and across thread boundaries i
    and pass them along in some sort of instantiable type, and however this is done, it is preferable to be able to
    later handle those errors the same way as all other thrown errors. One way to do this is through a thowing closure
    that either returns a value or thows an error, as detailed in
    [http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/](this blog post).
    [this blog post](http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/).
    However, this strikes me as odd as a closure can do anything and the desired behavior is very well defined. Through
    a simple extension to the familiar Result enum can serve this purpose.

  6. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 11 additions and 3 deletions.
    14 changes: 11 additions & 3 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -4,10 +4,18 @@ As Swift 1.0 did not include support for exceptions, a common error handling pat
    that either took on a value on success, or an error on failure. In a way, this was superior to using exceptions,
    since being a instantiable type, Results could be passed around freely, enabling asynchronous code to use the same
    error handling mechanisim as synchronous code. Using Swift's robust support for custom operators, this also enabled
    [http://fsharpforfunandprofit.com/posts/recipe-part2/](Railway Oriented Programming) for more functional oriented programers.
    [http://fsharpforfunandprofit.com/posts/recipe-part2/](Railway Oriented Programming) for more functional oriented
    programers.

    Swift 2.0 introduces throwable errors, which are similar to exceptions. However, like exceptions, thrown errors can
    only be caught in the same thread that threw them.
    Swift 2.0 introduces throwable errors, which are similar to exceptions. However, like exceptions, thrown errors
    propogate only down the call stack and can only be caught in the same thread that threw them. In order to propogate
    the errors upwards (such as to callback routines) and across thread boundaries it is necessary to catch the errors
    and pass them along in some sort of instantiable type, and however this is done, it is preferable to be able to
    later handle those errors the same way as all other thrown errors. One way to do this is through a thowing closure
    that either returns a value or thows an error, as detailed in
    [http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/](this blog post).
    However, this strikes me as odd as a closure can do anything and the desired behavior is very well defined. Through
    a simple extension to the familiar Result enum can serve this purpose.

    First we start with the familiar Result type:

  7. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 16 additions and 6 deletions.
    22 changes: 16 additions & 6 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,15 @@
    # Asynchronous Error Handling in Swift 2.0

    TODO: Write introduction
    As Swift 1.0 did not include support for exceptions, a common error handling pattern was to use a Result enum
    that either took on a value on success, or an error on failure. In a way, this was superior to using exceptions,
    since being a instantiable type, Results could be passed around freely, enabling asynchronous code to use the same
    error handling mechanisim as synchronous code. Using Swift's robust support for custom operators, this also enabled
    [http://fsharpforfunandprofit.com/posts/recipe-part2/](Railway Oriented Programming) for more functional oriented programers.

    First we start with the familiar, de facto standard Result type:
    Swift 2.0 introduces throwable errors, which are similar to exceptions. However, like exceptions, thrown errors can
    only be caught in the same thread that threw them.

    First we start with the familiar Result type:

    ```swift
    enum Result<T: Any> {
    @@ -38,7 +45,8 @@ extension Result {
    The unwrap method returns the value for ```swift .Success``` and throws the error for ```swift .Failure```.
    The initializer provides a convenient way to create a Result object for an arbitary block of code, simplifying
    the implementation of asynchronous functions.
    For example:

    Example:

    ```swift
    func findAnswerToTheUltimateQuestion(completion: (Result<Int>) -> ()) {
    @@ -54,11 +62,13 @@ func findAnswerToTheUltimateQuestion(completion: (Result<Int>) -> ()) {
    }
    ```



    ```swift
    doSomethingAsynchronously { result in
    findAnswerToTheUltimateQuestion { result in
    do {
    let x = try result.unwrap()
    //do something with x
    let answer = try result.unwrap()
    //Do something with the answer
    } catch let e {
    print(e)
    }
  8. BlameOmar revised this gist Sep 8, 2015. 1 changed file with 22 additions and 8 deletions.
    30 changes: 22 additions & 8 deletions async_error_handling.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,8 @@
    First we start with the de facto standard Result type
    # Asynchronous Error Handling in Swift 2.0

    TODO: Write introduction

    First we start with the familiar, de facto standard Result type:

    ```swift
    enum Result<T: Any> {
    @@ -7,7 +11,7 @@ enum Result<T: Any> {
    }
    ```

    Next, we add a simple extension
    Next, we add a simple extension:

    ```swift
    extension Result {
    @@ -31,16 +35,26 @@ extension Result {
    }
    ```

    The unwrap method returns the value for ```swift .Success``` and throws the error for ```swift .Failure```.
    The initializer provides a convenient way to create a Result object for an arbitary block of code, simplifying
    the implementation of asynchronous functions.
    For example:

    ```swift
    func doSomethingAsynchronously(completion: (Result<Int>) -> ()) {
    let result = Result {
    //any number of statements that may potentially throw
    return 42;
    }
    func findAnswerToTheUltimateQuestion(completion: (Result<Int>) -> ()) {
    //Computers are much faster today than they were in 1978, so this only takes a week
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1000*1000*1000*60*60*24*7), dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
    let result = Result {
    //any number of statements that may potentially throw
    return 42;
    }

    completion(result);
    completion(result);
    }
    }
    ```

    ```swift
    doSomethingAsynchronously { result in
    do {
    let x = try result.unwrap()
  9. BlameOmar renamed this gist Sep 8, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  10. BlameOmar renamed this gist Sep 8, 2015. 1 changed file with 11 additions and 1 deletion.
    12 changes: 11 additions & 1 deletion async_error_handling.swift → async_error_handling
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,15 @@
    First we start with the de facto standard Result type

    ```swift
    enum Result<T: Any> {
    case Success(T)
    case Failure(ErrorType)
    }
    ```

    Next, we add a simple extension

    ```swift
    extension Result {

    init(_ f: () throws -> T) {
    @@ -22,7 +29,9 @@ extension Result {
    }
    }
    }
    ```

    ```swift
    func doSomethingAsynchronously(completion: (Result<Int>) -> ()) {
    let result = Result {
    //any number of statements that may potentially throw
    @@ -39,4 +48,5 @@ doSomethingAsynchronously { result in
    } catch let e {
    print(e)
    }
    }
    }
    ```
  11. BlameOmar created this gist Sep 8, 2015.
    42 changes: 42 additions & 0 deletions async_error_handling.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    enum Result<T: Any> {
    case Success(T)
    case Failure(ErrorType)
    }

    extension Result {

    init(_ f: () throws -> T) {
    do {
    self = .Success(try f())
    } catch let e {
    self = .Failure(e)
    }
    }

    func unwrap() throws -> T {
    switch self {
    case let .Success(x):
    return x
    case let .Failure(e):
    throw e
    }
    }
    }

    func doSomethingAsynchronously(completion: (Result<Int>) -> ()) {
    let result = Result {
    //any number of statements that may potentially throw
    return 42;
    }

    completion(result);
    }

    doSomethingAsynchronously { result in
    do {
    let x = try result.unwrap()
    //do something with x
    } catch let e {
    print(e)
    }
    }