In fact, it's even worse than that. If the Store() caller goes to sleep between setting the type and storing the pointer, it causes every Goroutine that calls Load() to block. They can't make forward progress if the store caller hangs.
Where does this go to sleep: https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/...
It looks like a CAS busy loop with preemption disabled, to me.
Could you elaborate how "much every other language" implement it?
Interfaces don't have a zero type, which means that we can't have an atomic.Value which stores Shape. Atomic Value would be much easier to reason about if it had store semantics similar to a regular `var foo Shape = ...`. One of the other comment threads talked about generics helping this, so maybe there is hope.
var bestShape atomic.Value
bestShape.Store((*Circle)(nil))It just had nothing to do with atomicity; it means something specific, not just “I like the failure mode.”
type shapeContainer struct { Shape }
The usual way to use atomic.Value is by writing strongly-typed wrappers anyway, so that doesn't affect your codebase beyond about 3 lines.
How does this mean it's non-atomic? As far as I know you can still never Load() a partial Store(). (Also, even if it was possible, this would never be a good idea...)