There are a variety of approaches to tackle this problem, but the one we think would be the best fit is the implementation of AtomicReference in the swift-atomics package.
I started trying to rewrite some code that uses swift-atomics today that uses the AtomicReference type and realized that I don't have that type in the std lib. Anyone have recommendations on what to do instead?
I agree that the Swift Standard Library should come with out-of-the-box support for atomic strong references. It missed SE-0410 because the implementation in swift-atomics needs to invoke the swift_retain_n/swift_release_n entry points in the Swift runtime, and we did not have capacity to figure out how to do that properly. (The package is most definitely not doing it right -- we want to do a better job.)
We did ship all other necessary primitives, though (the most prominent being atomic operations on the WordPair type), so as long as you solve the retain_n/release_n situation, it should be reasonable straightforward to directly port the algorithm in swift-atomics to struct Atomic.
We've also shipped struct Mutex since then, and a mutex protecting a class instance works as a quick-and-dirty substitute for an atomic strong reference. (The obvious drawback is that Mutex isn't a lock-free solution; whether that is a problem depends on your use case.)
I have an unfinished PR that attempts to make progress on allowing Swift code to invoke those problematic runtime entry points. My full plan was to subsequently expose new Swift builtins that we could wrap in new Unmanaged API (Unmanaged.retain(by:)/.release(by:). I do still believe that is what we need, but I did not have the energy to work through the pushback I got from compiler experts at the time.
Note: calling the preexisting Unmanaged.retain()/.release() in a loop is not a viable substitute; we really do need to do multiple increments/decrements of the refcount in a single operation, or the construct would typically perform far worse than Mutex.
Note 2: while it may seem tempting to work out your own implementation for atomic operations on strong references, beware that it is quite a challenging task. (Very fun though!) So unless you have a month or two to do it, I'd recommend simply using Mutex or porting the algorithm from swift-atomics.
Hmmm... I was afraid of that. :) I need to go look at my previous code, but now that you mention it I remember some previous conversations (this one for example) where retain_n/release_n were a problem in Playgrounds and I solved it with the looping technique.
Curious as to why that is such a big deal to expose when the single versions seem to be fine.
Swift’s standard library doesn’t yet have AtomicReference. For now, wrap your class in Unmanaged and use ManagedAtomic<Unmanaged?> to handle atomic swaps safely. Be careful with manual retain and release to manage memory properly. Alternatively, use locks or actors.
Not from me! Ownership-aware containers are keeping me busy.
One way to make progress without implementing new compiler builtins would be to add the new noncopyable atomic strong reference type to the swift-atomics package, using the preexisting hack to invoke retain_n/release_n that's already in place there. (Which is not to say it would be difficult to add the new builtins -- one would just need to convince some compiler/runtime folks to spend time reviewing the changes, and work through the notes, as usual.)
I think shipping in a package first also tends to help keep the eventual proposal review discussion grounded in reality.