`guard` capture specifier for closure capture lists

I'm mostly a lurker around here, but this one is something that I've been giving a lot of thought to, so I thought I might actually weigh in.

We can talk ourselves in circles all day about the philosophical implications of optionals — and people regularly do — but I think there will always be a little bit of a divide between the people who view the inconvenience of optionals as a barrier to clear code and the people who see that inconvenience as a significant language feature that forces developers to explicitly account for edge cases. @jrose makes some good points about why this pattern is often the beginning of other troubles, and did a perfect job of characterizing why I often think the semantic of something like unowned is underused in these contexts, but addressing those concerns is really above my proverbial paygrade. So I'll focus on the hypothetical of if this existed.

I think the more important thing here is the question of how this will impact debugging, especially for the beginning Swift developer. In my observation, [weak self] is already a knee-jerk default choice for many developers starting out even when a closure has no chance of causing a retain cycle (something that can cause interesting bugs if an object has to register a certain piece of work was finished, for example), because the safety is reassuring. In that regard, [guard self] would become a habitual behavior for many Swift users virtually overnight, and unfortunately, as currently proposed, it seems to me like this could create a very beginner-hostile situation during debugging.

Probably the most common reason you'd lose self in a closure like this is some kind of race. This means that for most beginning developers, the first time they're not seeing their closure work correctly may be one of the most difficult bugs they've ever had to troubleshoot. Add on top of that the fact that it would not really be possible to breakpoint inside the closure and see that this implicit guard statement is the source of one's problem.

Maybe the solution to this situation is not necessarily a silent failure from a guard, but an assertion? In development settings, this would give you very clear visibility into potential issues as they crop up, and it would indeed be incredibly difficult to ignore that there's now a near-invisible bug in the app, but in production, users wouldn't see the issue. Perhaps an [assert self] or [expect self] might be a way to preserve this functionality while still retaining some kind of visibility into the mechanics of what's going on?

4 Likes