ValueSemantic protocol

No, that's a good point. I guess that leads to: ValueSemantic refines Clonable which refines ActorSendable.

Ah, now I see what you're up to. Thanks for explaining. To do that I guess you need to identify all the value-semantic adapters needed to build all the value-semantic types we'll ever want. Sounds hard to me.

Perhaps that’s too constraining, but iirc the implementation of things like Array are essentially a class wrapped in a CoW like abstraction.

Yeah, sort of… but I think you'll find if you try to encapsulate all the value semantics in adapter types, you can't efficiently implement lots of the mutations. CoW does not actually copy in all cases where the buffer is not uniquely referenced; if you do that for an insertion at the beginning of the array, for example, you end up writing the same memory twice.

Anyhow, I think it's an interesting exercise to try. Good luck!

What would be the relationship between these and the built-in assignment operator? Would let x = y call y.clone() if the type conforms to VS?

Nope, I'm not proposing that. C++ interop may imply that we'll get eagerly-copied value types with dynamic storage eventually, but I'm not comfortable adding that to the core language as a byproduct of solving the value semantics problem.

Actually I'm curious - do we want to make sense for things that are value semantic but not threadsafe? E.g. a CoW type that isn't implemented with atomic RC?

Not saying this is a good thing, but we could implement that model and having ValueSemantic be separate from ActorSendable to model this. Array would conform to both, but NonAtomicCoWArray could conform to VS but not AS.


I don’t think we do want to (though note this is not about what most people think of as “threadsafe types,” whose instances can be shared—not just copied or moved—across threads). Especially with the cost of uncontended atomic operations coming down, carving out a special category for types less threadsafe than Int doesn’t make sense to me. The principle of concept requirement clustering says that, if we are going to have ActorSendable, these things go together.

I have some serious reservations about actors, but that’s mostly a different story.

On further thought, the refinement of ActorSendable doesn't even really make sense as a definition of "value semantics", because the set of things that are sendable-as-self includes among other things actor references, references to safe concurrent data structures, and unique references to isolated object graphs, none of which probably meet our intuition of what "value type" normally means. If a refinement of ActorSendable makes sense as a way of enabling specialized behavior (such as collections sending as self when their elements send as self), then ValueSemantics would be the wrong concept to tie to that specialization.

At least until Swift gains move-only types, these properties hold for every type. The value of a class type is the reference. It seems to me that the closest thing you can get to a type level "value semantics" concept in Swift is ultimately the "copyable" ability.


No they do not, but I can't understand why you would think that implies that the refinement doesn't make sense. It seems as though maybe you're really just saying there should be an intermediate “sendable-as-self” protocol.

Not in many programmers' mental programming models, and definitely not for some immutable final classes. If that were the case we wouldn't have === distinct from ==, we wouldn't allow Equatable conformance for classes, etc.

As I say further along in that post, any type could conform to ValueSemantic and the meaningfulness of that conformance depends on having a definition of “value” for the type. If you want to say every class “has value semantics” but its value is reflected only by ObjectIdentifier(x) and ===, that's your perogative, but I don't think that will be a very useful definition for most people.

1 Like

Should we consider adding a nonmutating keyword for class functions & computed properties to let them get in on the fun?

Well, that again gets to the point that you can't really define a notion of "value" independent of some set of operations that apply to that notional value, and that it's the properties of the operation that ultimately matter. As is, you can define a value over some set of operations for every type.

Yes, and what I'vewe've done is to tie “value” and “safety” together in such a way that they allow us to reason about the behavior of operations on compositions of types whose notional value has been defined by the programmer, without repeating the same mental work for every single new operation that's written. These are the common cases that it's important to be able to work with most easily. And, I've explained how to extend the model to cover all compositions in a way that builds on the basic model.

1 Like

Yes, I generally agree with you, but for a different reason. Swift runs on a lot of non-apple platforms and that is important to consider. My rationale for agreeing with you is just that it fragments the world too much and would cut against the goal of making this safe by default. We could definitely model this, but it isn't worth it IMO.


1 Like

That's actually the same reason; the principle of concept requirement clustering is all about avoiding fragmentation. The granularity of concepts should be enough to make the important distinctions between models, not every conceivable distinction. I don't think the category of types that are less threadsafe than Int is important enough to warrant the complexity that introducing a separate concept adds. No matter what the cost of atomic refcounting is (and there are ways to mitigate those costs), people still want to program with threads, so we simply don't often hear of types in that category playing a crucial role.

P.S. (and this is really incidental) I assumed that whatever advances Apple silicon was making in the efficiency of atomics was likely to be occurring across the industry. Without asking you to reveal any trade secrets, of course, I suppose you might have some insight into that. Care to comment?

Credit where it's due

The statement above, as I originally wrote it, hasn't been sitting right with me, so I've made a correction. I mean this: if I managed to finally write down a usable definition for ValueSemantic, it's only because of the work we did here together.

In particular

  • if @Chris_Lattner3 hadn't prodded me to start the thread, it wouldn't have happened.
  • @anandabits's post yielded the crucial insight that if value semantics was to be used for thread-safety then a large category of operations had to be considered unsafe, and that category included all the operations that expose reference semantics on types that would otherwise be considered values.
  • Everybody who engaged in the discussion provided the environment of focus and collective inquiry that I, at least, depend on for insight.

Lastly I want to thank everyone for an experience that reminded me of why I believe so strongly in collaborative open-source development.



Great point, completely agreed.

I don't know anything about Apple Silicon so I'm afraid I can't say anything concrete here, but I can wildly speculate like any other industry observer :-) I would guess that they added atomic memory operations that have looser memory consistency model than the default ARM model (and certainly better than the X86 model), more aligned with the RISC-V relaxed consistency atomics. iPhones have had more efficient atomics than Intel processors for a long time AFAIK.

That said, I'm far from an expert on this and have no insider knowledge, I expect it will become more public as the hardware becomes more available.



I haven't had time to engage with this thread yet, but let me just pop in to note that "semantics" is not a plural noun and cannot have its s removed. While "semantic" is indeed an adjective, it does not mean "having (these) semantics" but "related to or expressing meaning", and "value-semantic" is not in use.


Since Swift protocols carry semantic meaning, one could argue that having “semantic(s)” in the name at all is repetitive.

If that argument carries the day, we could call it AnyValue to be consistent with AnyObject. Given that AnyObject conformance is implicit, this is especially interesting if we go with implicit conformances to AnyValue.


I’ve been turning it over in my head and I disagree that ‘value-semantic’ is incorrect as an adjective. I think the best analogy is to a well-established term like ‘set-theoretic,’ meaning something like ‘related to set theory.’ Note that the term is not (or at least, not as commonly) ‘set-theoretical,’ even though the adjective from ‘theory’ is usually ‘theoretical.’ This suggests to me that ‘set-theoretic’ is best thought of as the adjective derived directly from the term ‘set theory,’ rather than being derived directly from ‘theoretical’ with ‘set’ tacked on the front. Similarly, it seems quite reasonable to derive an adjective from the noun phrase ‘value semantics’—and what else would it be, but ‘value-semantic’? Yes, the meaning is different than the simple composition of the meanings of ‘value’ and ‘semantic,’ but that’s just as ‘set-theoretic’ means something a little different than just ‘theoretical and related to sets.’


I also haven't followed all of this thread, but any way to make this implicit would be nice. Otherwise pretty-much every wrapper will need to add conditional conformances to indicate that they preserve the value-ness of the thing they wrap:

extension Optional: ValueSemantics where Wrapped: ValueSemantics {}
extension Slice: ValueSemantics where Base: ValueSemantics {}
... etc

LazyMapCollection and LazyFilterCollection may or may not have value semantics depending on the map/filter closure.