Why does 'defer { do { ...' jump the queue?

In real life code, I want to have a defer issued "up top" of a method, but in one edge case I'd like to have another defer that runs before the original one (now thinking about this I may be able to solve it in a traditional sense).


I saw something online that suggested using 'defer { defer { <code> } }' In fact that does work, but generates a warning in Xcode 11b4-beta, with a fix suggestion of using 'defer { do { <code> } }'. That actually works - but I don't understand why!


var goo = 0
while goo < 10 {
  defer { print("LAST", goo) }
  defer { defer { print("(Want First)", goo)  } } // want it to execute before the LAST print but clang warning
  defer { do { print("First") } }                 // what the compiler tells me to do
  goo += 1
}


Console output:

First
(Want First) 1
LAST 1


So the double defer does do what I want, which I understand, and the 'defer-do' also works, but I'd l;ove to know why it works!

Accepted Reply

It does not "jump the queue".

Swift reference explains the order of multiple defer:


« If multiple defer statements appear in the same scope, the order they appear is the reverse of the order they are executed. Executing the last defer statement in a given scope first means that statements inside that last defer statement can refer to resources that will be cleaned up by other defer statements. »

Apple Inc. « The Swift Programming Language (Swift 4). » Apple Books.


May also read this, to understand how defer are 'stacked'

h ttps://medium.com/@rwgrier/swift-defer-statement-e16526b34f93


do just asks for execution, so

defer { do { print("First") } }

is the same as

defer { print("First") }

As for

defer { defer { print("(Want First)", goo) } }

you stack a defer statement in the "defer stack" which itself stacks its statement.

Not sure it is very use to use such constructs, but fun it works.


Why did you need to defer defer ? What do you expect that you could not get with just

defer { print("(Want First)", goo) }

Replies

It does not "jump the queue".

Swift reference explains the order of multiple defer:


« If multiple defer statements appear in the same scope, the order they appear is the reverse of the order they are executed. Executing the last defer statement in a given scope first means that statements inside that last defer statement can refer to resources that will be cleaned up by other defer statements. »

Apple Inc. « The Swift Programming Language (Swift 4). » Apple Books.


May also read this, to understand how defer are 'stacked'

h ttps://medium.com/@rwgrier/swift-defer-statement-e16526b34f93


do just asks for execution, so

defer { do { print("First") } }

is the same as

defer { print("First") }

As for

defer { defer { print("(Want First)", goo) } }

you stack a defer statement in the "defer stack" which itself stacks its statement.

Not sure it is very use to use such constructs, but fun it works.


Why did you need to defer defer ? What do you expect that you could not get with just

defer { print("(Want First)", goo) }

As far as I know, multiple defer statements are always executed in reverse order. You don't need any tricks to reorder them in the way you describe.

`defer` works in the nearest enclosing code-block in Swift.


In your doubled `defer`, the code-block for the inner `defer` is here:

  defer { defer { print("(Want First)", goo)  } } 
        ^---------------------------------------^


If you know other languages which has try-finally, the following pseudo code explains what's happening in doubled `defer`.

  defer {
      try {
      } finally {
           print("(Want First)", goo)
      }
  }

So, doubled `defer` is simply no meaning. The inner `defer` has no effect to outer code-block.


I'm curious where you have found defer-defer or defer-do, both useless.