It's awesome to see that someone has been exploring this topic to the point of implementing a proof-of-concept! I spent quite a bit of time exploring how we could add language support for value semantics to Swift a couple years ago. As I'm sure you are well aware, there are a lot of subtleties involved in getting this right.
If you're interested in seeing the draft I had been working on you can find it here: ValueSemantics.md · GitHub. This draft has flaws (which is why it was never shared on SE), but may also have some points of interest.
What syntax do you propose for overriding the default semantics?
I think this is the right choice. In my experience, most Swift programmers don't understand all of the subtleties involved in value semantics and preserving referential transparency. By choosing this default programmers would be able to know that referential transparency is preserved if their value types compile without error or additional annotation.
However, there are plenty of use cases for value types that do not involve strict value semantics. I think we also need a way to flip the default for a specific value type. This would be a somewhat advanced feature, but without it implementing these value types would be more cumbersome than necessary. It would also be a huge aid in source migration - all existing value types would be migrated to not have strict value semantics. Users would opt-in to value semantics for their types at their leisure.
The way I had approached this was to require a type with strict value semantics to provide value-semantic implementations of all protocol requirements unless those requirements had specifically been annotated as not having value semantics (see my question above re: syntax for modifying the default).
As far as syntax, I would prefer to see a magic AnyValue protocol providing the value-semantic analogue of AnyObject. AnyValue would carry strict value semantics: value types without strict value semantics would not conform.
This is unnecessarily restrictive and would not support all of the APIs in the standard library, for example Int.random overloads that don't take an inout generator. Another good example from Foundation is Date(). I think it's find for a type with strict value semantics to have some APIs that do not have strict value semantics as long as those are explicitly annotated and differentiated in the type system.
How are you differentiating these syntactically? You haven't mentioned pure functions at all. Do you see any distinction between "value semantic" functions and "pure" functions?
FWIW, @Joe_Groff has in the past suggested we might introduce an => arrow with stricter semantics than the -> arrow we have today.
There has also been quite a bit of discussion about the fact that people seeking stricter semantics aren't always looking for the same thing. For example, data race free is not the same as referentially transparent. It may be useful to model these behaviors more generally as effects (or absence of effects).
This is not true. inout parameters of a type that has strict value semantics are simply an alternate way to return a result. They do not break referential transparency. Language support for value semantics must be able to understand this.
I don't follow what you mean here exactly. Are you talking about functions like map? What we need in that context is something like rethrows which says that map preserves value semantics / referential transparency, but that its semantics ultimately depend on those of the transform.
I believe a similar mechanism may be necessary for generic types. I view a type such as Array as preserving value semantics rather than having value semantics. The elements of the array are a fundamental part of the value an array represents and if they do not have value semantics the array doesn't really have value semantics either.
I'm skeptical of creating an escape hatch like this for specific APIs. However, I think it's unlikely that we will be able to add language support for value semantics and be able to implement foundational data structures like Array as a type with strict value semantics unless there is an escape hatch along the lines of Rust's unsafe.
Can you go into more detail on how you would recognize standard library collections as having value semantics in the presence of an implementation that allocates memory, uses CoW, etc? Identifying a model that works for sophisticated implementations of strict values such as these is difficult, yet essential. It isn't clear from what you've written thus far how that would work.
This view is true in some sense, but I also think from a pragmatic point of view it is extremely useful to acknowledge that many types have members that predominantly have strict value semantics. Saying Int is a value (i.e. has strict value semantics) is an extremely useful cognitive shorthand. Modeling this directly in the language would also help to highlight members which have semantics that are exceptions to the default semantics of the type (which is something that I think is pretty important).
Further, value semantics is about more than just referential transparency of operations. The state associated with a value matters.
A value should only store state that is essential to the representation of its meaning (as defined by equality). This may include state that is incidental to the meaning if that state is essential to the implementation, however incidental state must be handled carefully. For example, Array.capacity is not referentially transparent as it could have different results for equal arrays. We need to model types with strict value semantics in the language in a way that understands incidental members if we wish to have referentially transparent value semantics in Swift.
Beyond the issue of incidental state, if I store a value of a type with strict value semantics internally in a library I should not have to worry about unexpectedly retaining a handle to a resource, etc. If you say that types like Array unconditionally have strict value semantics then you are forced to deal with the concern that a so-called strict value may actually retain arbitrary resources.