The biggest issue I have with Swift today is the lack of support for atomics. This is a particularly important issue because there's no workaround here, short of writing my code in Objective-C, but that can't interoperate with Swift value types or Swift generics (for the most part). The only partial workaround I have is the use of OSAtomic.h, for those cases where it actually provides the operation I need, but even that is risky because it's not actually guaranteed to be valid (because Swift operates on a writeback semantic model, there's no guarantee that e.g. calling
OSAtomicCompareAndSwap32(value, newValue, &value)
will actually behave as desired; Swift is free to make a local copy of the value, pass a pointer to that to the function, and then non-atomically write that back to the original location). And it often doesn't provide the operation I need anyway.Every single big Swift project I've done has run into this limitation. I usually end up working around it by giving up on the idea of atomic operations and using a spinlock (although
OSSpinLockLock(&spinlock)
is not actually guaranteed to work, for the same reason as above). But this is disheartening, because I'm throwing away performance for no reason. And when I'm writing extremely performance-criticial code (such as code that needs to handle in realtime the data coming from an AVCaptureDevice) this especially makes me worry.I get that atomics are hard, and that Swift may want to come up with some high-level model of threadsafe operations that doesn't match C++11's std::atomic. But at a low level LLVM operates on the same model as C++11's std::atomic, and having these low-level operations exposed now would be extremely helpful. At such time as Swift comes up with a high-level threadsafe model, it will presumably be built on top of these same low-level operations anyway.
Of course, C++11's
std::atomic
actually doesn't guarantee lock-free behavior, and it uses template magic to use locks when necessary. This is not what I'm asking for. What I'm really asking for is something more like Rust's atomic model, which exposes distinct types for the 4 types it can guarantee are lock-free (Bool, pointer-sized signed integer, pointer-sized unsigned integer, and pointer), and methods on these types for the various valid atomic operations. A slightly higher-level Atomic<T>
matching C++11's std::atomic
could be implemented later on top of this, if Swift ever grows the ability to specialize the memory representation of an atomic type, or perhaps some other high-level atomic model. The important aspect here is that the atomic capabilities of LLVM IR should be exposed to the language, such that the Swift stdlib, or us third-party devs, can write proper thread-safe implementations on top of this.As it stands today, because of the lack of atomics, I worry that a lot of Swift code that's being written isn't actually thread-safe, and that any code that is threadsafe is unnecessarily slow. I know I've personally seen a lot of code written by coworkers or by third parties that accidentally perform concurrent access of a shared value from multiple threads, without meeting the narrow requirements of LLVM IR to have this access be defined (e.g. that in the happens-before partial order there is only a single write to that location that is visible to the non-atomic read). This sort of thing often seems to work in practice, but because it technically returns an undefined value, optimization may cause it to break, or more generally, the code may not actually race most of the time but when it does it behaves incorrectly. Granted, including proper Atomic support won't actually prevent anyone from writing thread-unsafe code, but it will allow the correct threadsafe code to be written by others, and its existence will hopefully remind people that data races are a legitimate issue.