`for await` and `weak self`

I don't know whether there's official documentation that gets to the level of implementation detail you might be interested in, but the Weak References section of the Automatic Reference Counting page of The Swift Programming Language book might get you part-way.

A few posts from the Weak Let pitch (which has since been accepted and implemented) that may also be instructive in forming a mental model:

tl;dr: weak references are a special type of value that at read time either produces a value if the referenced object still exists, or returns nil; this unwrapping behavior is consistent in all Swift contexts.

To that end, in this example:

the compiler and optimizer are, to the best of my knowledge, not allowed to hoist the self check outside of the loop in the general case, because it changes the semantics of the loop, same as above:

  1. Setting self.lastState may have side effects which would lead self to be deallocated, normally breaking out of the loop early; if self is unwrapped outside of the loop and retained, it may unexpectedly loop over all of states
  2. In the absence of side-effects, states may be an extremely large (or even infinite) sequence of values such that hoisting the check outside the loop might have a significant performance impact (or even turn what is normally a terminating loop into an infinite loop)
  3. The iteration itself may have side effects: types' Sequence and IteratorProtocol conformances can run arbitrary code, such that terminating at different points may have visible side effects

It's possible that, if the optimizer has enough static knowledge about both self and states that it can prove none of these are possible, and therefore the check can be hoisted out, but I'd wager this'd be an expensive and invasive check for little potential win. (And, to the best of my knowledge, optimizations like this are largely implementation detail, and not documented publicly.)

3 Likes