Unnecessary self weak dance

I saw this pattern which in a distilled form is equivalent to:

struct S {
    init(closure: () -> Void) {}
}

class C {
    func foo() -> S {
        S { [weak self] in 
            guard let self else { return }
            // do something
        }
    }
}

It doesn't make sense to me as the closure is non escaping so no way self could be gone. Or is there a legitimate usefulness to this pattern?

If it's useless, should't Swift put a warning about unnecessary weak capture?

1 Like

The S doesn't add anything. It simplifies slightly.

func f<T>(_: T) { }

class C {
  func foo() {
    f { [weak self] in _ = self }
  }
}

There are infinite situations where a warning could be added but has never been.

It doesn’t make sense to do so from the code execution perspective, however from the project perspective “always use weak captures in closures“ can be a useful generalization :man_tipping_hand:

  • It’s better to have redundant weak captures than memory leaks
  • It’s better to have thoughtfully written code than redundant weak captures
  • Maybe for some folks thoughtfully written code is not an option and it’s fine :sweat_smile:

It makes no sense, but a large number of Swift developers are under the mistaken impression that [weak self] is a reasonable default, and some even (regrettably, imho) require it using linters or other tooling.

2 Likes

The closure still holds a strong reference to self during execution because of the guard statement. So I think the explicit weak capture is ambiguous and confusing.
EDIT: on a second thought this isn't a valid reason because it's true in those scenarios that requires weak capture too.