I've avoided this topic for long enough, so let's do this.
Let's start with a plain English definition:
Definition:
A type has value semantics when mutation of one variable of that type can never be observed through a different variable of the same type.
-
This applies to more than just variables (e.g. you can't observe a mutation to a variable through a
let
; you can't observe a mutation of oneArray
element from another), but the semantics of Swift ensures that a type meeting the definition also covers those cases. -
By this definition, immutable types have value semantics trivially. If you want to emphasize that you're interested in more than just immutable data, you can call it mutable value semantics, but I'm going to leave out “mutable” in this discussion.
Formalizing this definition further for Swift is hard, since what it means to "mutate a variable" and "observe something through a variable" is tough to describe, especially when it comes to classes.
Collapsed the part that is mostly wrong
I think you need a notion of “purity” that allows mutation, but that is hard to nail down. I can describe it roughly as:
Definition
A function is value-pure if and only if it:
- calls no methods on class instances, and
- mutates no global variables, and
- calls no functions or methods that aren't value-pure.
Then you can say a type T
has value semantics if and only if it's impossible to write a unary value-pure function whose result when passed a variable b
of type T
changes after being passed a variable a
of that type:
var a, b: T
...
let r0 = f(&b)
_ = f(&a)
let r1 = f(&b) // r0 must be equivalent to r1 for all possible value-pure functions f
Among the other weakness in this description that I've undoubtedly missed
- it doesn't work for immutable class instances.
- “equivalent” isn't well-defined, and we're not going to require
Equatable
. - I've relied on a notation of mutation in defining value-pure, which is circular
- the value-pure functions you can write depends on the scope you're in—e.g. I could certainly violate value semantics from inside the implementation of
Array<Int>
but it still has value semantics. - you probably want a back door for “
unsafe
” functions (I just keep thinking of new bullets to add!)
It's possible someone can figure out how to close these holes, but in the end it might just be better to stick with the plain English definition of what ValueSemantic
means.