The distinction between checked and unsafe continuations in Swift – Donny Wals


Printed on: April 24, 2022

Whenever you’re writing a conversion layer to rework your callback based mostly code into code that helps async/await in Swift, you’ll usually end up utilizing continuations. A continuation is a closure which you could name with the results of your asynchronous work. You have got the choice to go it the output of your work, an object that conforms to Error, or you’ll be able to go it a End result.

On this publish, I received’t go in-depth on displaying you how you can convert your callback based mostly code to async/await (you’ll be able to discuss with this publish if you happen to’re involved in studying extra). As an alternative, I’d like to elucidate the distinction between a checked and unsafe continuation on this quick publish.

For those who’ve labored with continuations earlier than, you’ll have seen that there are 4 strategies that you should utilize to create a continuation:

  • withCheckedThrowingContinuation
  • withCheckedContinuation
  • withUnsafeThrowingContinuation
  • withUnsafeContinuation

The principle factor that ought to stand out right here is that you’ve the choice of making a “checked” continuation or an “unsafe” continuation. Your intestine would possibly let you know to all the time use the checked model as a result of the unsafe one sounds… effectively… unsafe.

To determine whether or not that is right, let’s check out what we get with a checked continuation first.

Understanding what a checked continuation does

A checked continuation in Swift is a continuation closure which you could name with the end result of a conventional asynchronous perform that doesn’t but use async/await, usually one with a callback closure.

This would possibly look a bit as follows:

func validToken(_ completion: @escaping (End result<Token, Error>) -> Void) {
  // ultimately calls the completion closure
}

func validTokenFromCompletion() async throws -> Token {
    return strive await withCheckedThrowingContinuation { continuation in
        validToken { end in
            continuation.resume(with: outcome)
        }
    }
}

The code above is a quite simple instance of bridging the standard validToken methodology into the async/await world with a continuation.

There are a few guidelines for utilizing a continuation that you just want to remember:

  • You must solely name the continuation’s resume as soon as. No extra, no much less. Calling the resume perform twice is a developer error and may result in undefined conduct.
  • You’re accountable for retaining the continuation and calling resume on it to proceed your code. Not resuming your continuation signifies that withCheckedThrowingContinuation won’t ever throw an error or return a worth. In different phrases, your code will probably be await-ing eternally.

For those who fail to do both of the 2 factors above, that’s a developer mistake and it’s best to repair that. Fortunately, a checked continuation performs some checks to make sure that:

  • You solely name resume as soon as
  • The continuation handed to you is retained in your closure

If both of those checks fail, your app will crash with a descriptive error message to let you know what’s incorrect.

After all, there’s some overhead in performing these checks (though this overhead isn’t monumental). To eliminate this overhead, we will make use of an unsafe continuation.

Is it necessary that you just eliminate this overhead? No, in by far essentially the most conditions I extremely doubt that the overhead of checked continuations is noticeable in your apps. That stated, if you happen to do discover a cause to eliminate your checked continuation in favor of an unsafe one, it’s necessary that you just perceive what an unsafe continuation does precisely.

Understanding what an unsafe continuation does

Briefly, an unsafe continuation works in the very same manner as a checked one, with the identical guidelines, besides it doesn’t examine that you just adhere to the principles. Which means that errors is not going to be caught early, and also you received’t get a transparent description of what’s incorrect in your crash log.

As an alternative, an unsafe closure simply runs and it would crash or carry out different undefined conduct while you break the principles.

That’s actually all there’s to it for an unsafe continuation, it doesn’t add any performance, it merely removes all correctness checks {that a} checked continuation does.

Selecting between a checked and an unsafe continuation

The Swift staff recommends that we all the time make use of checked continuations throughout growth, at the least till we’ve verified the correctness of our implementation. As soon as we all know our code is right and our checked continuation doesn’t throw up any warnings at runtime, it’s protected (sufficient) to change to an unsafe continuation if you happen to’d like.

Personally, I want to make use of checked continuations even after I know my implementation is right. This enables me to proceed engaged on my code, and to make adjustments, with out having to recollect to change forwards and backwards between checked and unsafe continuations.

After all, there’s some overhead concerned with checked continuations and if you happen to really feel such as you would possibly profit from utilizing an unsafe continuation, it’s best to all the time profile this primary and be sure that this swap is definitely offering you with a efficiency profit. Making your code much less protected based mostly on assumptions isn’t an ideal concept. Personally, I’ve but to discover a cause to favor an unsafe continuation over a checked one.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles