Isolated synchronous deinit #2

I think that would be highly unreliable. And in any case, too unreliable to build any real APIs around requiring this. I really would not want to have APIs which would crash on "released on wrong task", that sounds like a nightmare to hunt down.

I'm looking at this as someone designing the distributed tracing API, where very much you'd like to have a span "released in the right context", but since this would be unreliable and one could pass around a span or whatnot, this cannot serve as tool to implement such API, and we still need an explicit defer { span.end() } or withSpan {} APIs instead.

Task locals are a bad tool for this though; Since there is going to be programatic access to backtraces that would be the right way to debug such things, wouldn't it: [Pitch] Swift Backtracing API

And I'll once again bring up the future work topic where we were worried about giving too strong promises potentially preventing future optimizations. Like @kavon mentioned, spinning up tasks for every deinit is expensive, so we could try to cheat and reuse tasks someday but to do this efficiently, we should not guarantee any task local values in those deinitializers IMHO.

I'm not so concerned about a potential difference here to be honest... but it could be considered: adding a "barrier" to lookups is cheap and could be done before a deinit runs... but still, we'd have todo this before every deinit then? The cheapest and predictable thing I thought was "just leave nonisolated inits alone" and "don't dopy to ones where we need to spin up a task". Either way, one should not rely on the presence of locals in a deinit, and if you got them "lucky!" but don't rely on it in any way.

1 Like