I'd probably prefer that var b = a would just generate an error. You would have to explicitly copy or clone an immutable object in order to create the variable.
I'm glad I'm not the only one thinking this. What's the point of Swift being "safer" if this isn't an error (or at least a warning). The standard library even includes -[mutableCopy], so it's a established convention.
agreed; this would be a nice exception and I'm sure in a few places the compiler could pick this up to add warnings.
Alternatively get it to throw an exception if the array is modified.
Much better than some [[]] notation which just makes me think of multidimensional arrays
This is certainly my favorite too. Implicitness and sugar are only worth their weight when their semantics are obviously illusory. That's not the case with this copy-on-assign business.
I don't understand what semantics are illusory? Swift semantics for value types (including structs, arrays dictionaries and strings) are copy on assignment (return and argument passing). The fact that most of the copies are optimised out doesn't actually change the semantics.
If that's always made clear then it's probably fine. I haven't played around in Swift enough to know it to be true.
I'm used to the memory-free semantics where equality equivalates a mathematical variable with a value. Assignment doesn't have a place here and it works very well with immutable values. Only mutability needs the notion of assignment so that you have boxes to subject to mutation.
If I understand you correctly Swift does that. Only objects (defined as classes) are mutable reference types as far as semantics go.
Declaring constants with let has the effect you are talking about for equality. If you want to you can stick to that.
Where you declare a variable to contain a struct, dictionary or array with var you can mutate it but it only affects your copy so it is equivalent to creating a new instance with the updated vale and assigning it back to the same variable.
With the copy on write behaviour if there are no other variables or constants pointing to the original instance it can skip the copy for efficiency without affecting the semantics.
Yeah that makes perfect sense. The notion I'm getting at is where you say "declare a variable to contain". If you have only immutable objects then you can dispense with the idea of containment and use only equivalence. As an equivalent semantics you can have containment and copy-on-write everywhere. Under immutability they are the same.
The trouble is that if you try to have both "name-equivalence" and "containment" and mutable things. At this point, copy-on-assign almost works uniformly. Except unless something like
var a = x
var b = a
does not refer to three separate containers, only at most two if x were immutable. At that point I feel like the explicit copy-on-assign might be better.
I'm not sure how the behaviour isn't uniform (unless you are getting on to classes).
Taking your example assuming x has been declared let x = [1,2,3] then the code you show will behave exactly as if the array had been copied but underneath it would actually be sharing a single bit of memory and have skipped/postponed the copies.
If the next line was b[0] = 5 then a copy would be made so x and a would still be [1,2,3] and b would be a separate array [5,2,3].
The behaviour will be exactly the same as copy on assign. You might be able to identify that it hasn't copied with the identity operator === but why would you need to know?
No a has the value [1,2,3] still in that scenario. Copy on assign semantics is for constants and mutable variables.
Just tested in the playground:
var a = [1,2,3]
var b = a
a == b // true
a === b // true
b[0] = 10
a // [1,2,3]
b // [10,2,3]
b[0] = 1
a == b // true
a === b // false
a // [1,2,3]
b // [1,2,3]
I wouldn't recommend using === in production (except for objects of classes) either but for this demonstration it let me show the copy on write without going to assembly.
Glad we've reached a common understanding, I wasn't quite sure that I hadn't missed something.