apologies if you know this already, but a capture of a mutable local variable like this essentially places the value in a reference-counted 'box' that lives on the heap. this is why changes to the value are 'visible' across different execution contexts (this is nicely explained in this comment/thread).
as such, the issue here is less about 'race conditions' and consistency (though that is also something worth considering), and more about avoiding 'data races' (ah, and it seems you've authored a nice post on the distinction between those terms). the diagnostic prevents capturing these 'by-reference' captures in @Sendable
closures because such closures may execute concurrently, and mutations of the capture in such cases could cause data races.
the implementation for this concurrency diagnostic is quite conservative â it is currently based entirely on information present when typechecking, and doesn't use any kind of 'dataflow analysis', like that which powers region based isolation (though commentary suggests some more sophisticated analysis may be an eventual capability). and as a slight aside â one reason i think the diagnostics have to be (perhaps surprisingly) conservative in cases like this is that there's no way to 'tell' the compiler that a closure will be run at most once. so the compiler essentially has to assume a @Sendable
closure could be invoked multiple times, concurrently, and apply rules that ensure such cases are still safe.
in your specific example, assuming there are never any writes to the captured value, then i think the code should be data-race free (perhaps by definition), but it will require some source modifications[1] currently to convince the compiler that is the case.
a
let
or capture list item for immutable values, andMutex
or explicitunsafe
opt-outs for mutable cases. âŠī¸