Swift: do statements and labeled breaks

This snippet demonstrates some do-statement control flow. The do scope executes synchronously in code. So this example prints “Starting”, executes the do statement, then prints “Ending.”

 

print("Starting")
labelpoint: do {
    // Waits to execute until the scope ends
    defer{print("Leaving do scope")}
 
    // This will always print
    print("Always prints")
 
    // Toss a coin and optionally leave the scope
    let coin = Int(arc4random_uniform(2))
    print("Coin toss: " + (coin == 0 ? "Heads" : "Tails"))
    if coin == 0 {break labelpoint}
 
    // Prints if scope execution continues
    print("Tails are lucky")
}
print("Ending")

A couple of points to note:

The defer statement executes at the end of the do scope, regardless of the circumstances of it ending. You can return, you can break, you throw an error, whatever. If you leave the scope, the defer runs.

Use a label to break. There are any number of way to end a do scope but break requires a little extra care. Declare a label at the do statement. As far as I can tell, you cannot break to any other label in your app, just to the associated one. This example tosses a coin, and when it comes up head, breaks. The “Tails are lucky” line isn’t printed.

The great advantage of this flow is that it allows you to complete the do scope and continue execution on demand. The break provides a kind of “return” statement like you’d use in closures.

Any insights, thanks to Lily Ballard. Any mistakes are mine alone.

2 Comments

  • It seems like defer is an excellent candidate to replace patterns like goto cleanup in old C code.

  • Great post Erica.

    One quibble… your can break to and from any labeled loop, conditional statement, or do block as long as it encloses the line where your ‘break’. For example, you can enclose your example code’s do block inside a labeled for loop; then you could break out of that for loop, and not just the do block.

    With labeled loops, you can ‘continue’ instead of break, which just skips directly to the next iteration of the loop.

    Cheers!