Friday, March 1, 2024

How the Swift Compiler Knows That DispatchQueue.main Implies @MainActor

Ole Begemann (Mastodon):

A bit of experimentation reveals that it is in fact a relatively coarse source-code-based check that singles out invocations on DispatchQueue.main, in exactly that spelling.


Fun fact: since this is a purely syntax-based check, if you define your own type named DispatchQueue, give it a static main property and a function named async that takes a closure, the compiler will apply the same “fix” to it. This is NOT recommended[…]


The biggest benefit of Swift’s concurrency model over what we had before is that so many things are statically known at compile time. It’s a shame that the compiler knows on which executor a particular line of code will run, but none of the tools seem to be able to show me this. Instead, I’m forced to hunt for @MainActor annotations and hidden attributes in superclasses, protocols, etc. This feels especially problematic during the Swift 5-to-6 transition phase we’re currently in where it’s so easy to misuse concurrency and not get a compiler error (and sometimes not even a warning if you forget to enable strict concurrency checking).

Doug Gregor:

The @MainActor attribute is the general thing, and if DispatchQueue.main returned a MainDispatchQueue type whose async method took a @MainActor closure, we’d be all set. The problem with this specific case is that DispatchQueue.main already has a type (DispatchQueue), and you can’t change that type without affecting source compatibility. So you would need some generalization that tries to carry MainActor-ness along with the value. I suspect that such a generalization would generalize to, basically, just this API, so I didn’t pursue it. Given the choice between breaking source compatibility for DispatchQueue.main (which is everywhere), inventing a bespoke feature for these cases alone, or allow-listing this pattern to help more code “just work”… I think this was rhetorical right call. Maybe we should have also deprecated this pattern over to move to an API that does take a @MainActor closure, so the allow-list would become irrelevant over time.

Holly Borla:

You might be interested in this pitch which replaces @_inheritActorContext with a proper, non-underscored @inheritsIsolation attribute, including replacement in Task.init.

Der Teilweise:

Everything about warnings is completely broken in Xcode.

When I turn on the concurrency warnings in 15.3ß3, I get ~40 warnings that disappear half a second after I click them (and come back when I switch away from the file).


Comments RSS · Twitter · Mastodon

Leave a Comment