Hi everyone. The review for SE-0410: Atomics ran from October 23 through November 6. The language steering group has decided to return the proposal for revision on the following points:
The language steering group would like to see a compiler diagnostic for when
Atomic types are used in cases that would require dynamic exclusivity checking, namely when code attempts to declare an instance property of a class, a global variable, or escaped local variable as a
Atomic type. It is natural to think of atomic values as being mutable, making it tempting to declare them as
vars. However, it is almost always more correct to declare atomics as
let properties, since their atomicity allows for them to be safely updated even in typically “immutable” contexts without exclusivity checking or synchronization. There may be uses for knowing when code statically has exclusive access to an atomic property, to allow for safe “tearing” non-atomic access to the storage, but dynamic exclusivity checking is never appropriate for use in combination with atomics, so it is important to guide developers toward using
let for atomics in these situations. Designing this mechanism should be a focus point of the second round of review.
This property of atomics is likely to be shared with other concurrency primitives, particularly locks and lock-guarded containers, so it would make sense for this “diagnose when attempting to use with dynamic exclusivity” functionality to be a general language feature. However, for the time being, the language steering group recommends keeping this functionality specific to
Atomic. We believe that more experience with implementing additional concurrency primitives will help inform the design of that general feature, whether it is an independent attribute or if it’s tied to some other common implementation property of all of these concurrency primitive types.
The authors had originally pitched the new types introduced by this proposal as appearing in a separate module from the default-imported
Swift module, since atomics are a fairly advanced feature, and the authors didn’t want these types polluting the default namespace of all types. The language steering group agrees with this concern, and would like to see atomic APIs placed in a separate explicitly-imported module from the standard library. During the pitch discussion, concerns were raised about circular dependencies if the standard library’s core types themselves start to adopt atomics, leading to the proposal moving the atomic types into the core standard library itself. The steering group believes that those implementation challenges can be overcome, and that the separate namespacing is important for managing the developer experience. We recommend using a module named
Atomics as a starting point for discussion during the second round of review.
Some review discussion noted that, despite being closely related, the naming of these two protocols doesn’t follow a consistent theme. As a possible alternative, the language steering group suggests that
AtomicValue could be renamed as
AtomicWrappable (and that, for consistency,
Atomic<Value>’s generic parameter be renamed
Atomic<Wrapped>). We acknowledge that the existing names are currently used by the
swift-atomics package, and that maintaining consistency with the package will reduce friction for developers migrating their code to use the new standard library facilities, and that is a factor to consider in reevaluating the name during the next review cycle.
The language steering group also discussed the following review topics:
- It was pointed out that the
SIMDfamily of types do not conform to
AtomicValueas part of this proposal. Getting these types to conform would be difficult within the current constraints of the generics model, because a generic type may only conform to a protocol in one way, but the relationship between SIMD element types, vector size, and atomic storage is irregular and not easily parameterizable. The language workgroup does not think the implementation complexity of making
SIMDusable with atomics is worth the relatively small utility gained.
atomicMemoryFence(ordering: .relaxed)is a concept that exists as a composition of memory fence and ordering concepts, although its semantics are a complete no-op, since no “fence” is necessary to impose relaxed ordering of surrounding memory operations. The review discussion raised the possibility of banning this case. The language steering group does not see this as necessary, though, since it’s harmless, and preventing its use could lead to complications if we allow for abstraction over orderings in the future with improved constant evaluation abilities. A relaxed fence is merely useless, as opposed to being conceptually incorrect in the way that a releasing load or acquiring store would be.
- The proposal does not include interop with C or C++ atomics. Since the Clang importer currently completely ignores declarations involving atomic types, the language steering group believes that interop with atomics should be implementable in a nonbreaking, additive way, and this can be left as a future direction. The import functionality will have to be done in a platform-sensitive way, since C and C++ allow for locking atomic implementations, and atomic types may include storage for a lock in some or all cases, whereas Swift atomics are always lock-free. On some platforms, C++
_Atomicmay not necessarily be compatible as well.
- Several alternatives to the use of constant literal arguments for orderings have been discussed and rejected through the evolution of this proposal. One more idea was raised during the review, of using “view” types to express the different orderings and then placing the atomic operations on those views, so that code would read as
atomicVariable.relaxed.load(). This looks appealing, but it runs into similar problems as other alternatives with a combinatorial explosion of view types necessary for operations that require two ordering operands, such as compare-exchange.
- The proposal represents atomic operations that are unsupported by the current target by giving the affected types unavailable conformances to
AtomicValue. The language steering group agrees this is the right modeling. There is a concern that, as currently implemented in the compiler, use of unavailable conformances only raises a warning, but the language steering group sees this as a bug that should be fixed in the compiler.
Thanks to everybody who contributed to the review!