karelpeeters
05/19/2018, 7:39 AMx
.benleggiero
05/20/2018, 6:48 AMkarelpeeters
05/20/2018, 7:14 AM.allAll(...)
if you want to mutate or y = y + x
to make a new one.benleggiero
05/20/2018, 4:43 PMkarelpeeters
05/20/2018, 5:20 PMbenleggiero
05/20/2018, 5:43 PMSet
vs MutableSet
, Swift just has Set
, and whether it's mutable is decided by how it's declared. Mutable sets can be fields declared with var
, or function parameters declared with inout
. When you mutate a Swift value type, its copy-on-write system actually creates a complete memcopy of the original value, with your mutations applied. If the original is no longer accessible (its variable name was mutated or reassigned), it's immediately deallocated, so there's no memory bloat from this behavior.
So bringing it back to Kotlin, if there was just Set
and no MutableSet
, we could do this no problem:
var x = setOf<Foo>()
val y = setOf<Foo>(Foo.instance)
x += y // OK!
y += x // Impossible!
Here, x
would be a mutable Set
and y
is an immutable Set
. Because x
is a mutable value with copy-on-write semantics, its contents is copied to a new location in memory, mutated such that the contents of y
are appended to the end, and reassigned to the variable x
. The old contents are deallocated/garbage-collected/whatever.
On the next line, we have nonsense. Not only is y
an immutable set, but its pointer is also immutable (traditional val
behavior). So there is no =
nor +=
operator that would apply.
No more ambiguity, much more expressive and intuitive. I really hope Valhalla allows for this 🙏🏼karelpeeters
05/20/2018, 5:54 PMaraqnid
05/21/2018, 3:21 PMbenleggiero
05/21/2018, 4:33 PMstruct
, its value won't change from another thread or by passing it to a function (unless you use the inout
keyword)karelpeeters
05/21/2018, 4:36 PMbenleggiero
05/21/2018, 4:58 PMinout
on a function parameter allows the function to mutate the contents in a way very similar to how one usually passes things by reference, so there is rarely ever a reason to use the wrapper workaroundlet first = ["foo", "bar", "baz"]
var second = first // runtime takes note, but does not yet copy anything
print(second) // ["foo", "bar", "baz"]
var third = second // same situation
print (third) // ["foo", "bar", "baz"]
third [1] = "qux" // the contents of `first` are copied into `third` and then mutated
var fourth = third
print (first) // ["foo", "bar", "baz"]
print (second) // ["foo", "bar", "baz"]
print (third) // ["foo", "qux", "baz"]
print (fourth) // ["foo", "qux", "baz"]
second.remove(at: 2) // contents of `first` are copied and mutated
print (first) // ["foo", "bar", "baz"]
print (second) // ["foo", "bar"]
print (third) // ["foo", "qux", "baz"]
print (fourth) // ["foo", "qux", "baz"]
fourth.append("hoge")
print (first) // ["foo", "bar", "baz"]
print (second) // ["foo", "bar"]
print (third) // ["foo", "qux", "baz"]
print (fourth) // ["foo", "qux", "baz", "hoge"]
func mutate(_ array: inout [String]) {
array.append("hello")
}
mutate(&second)
mutate(&fourth)
print (first) // ["foo", "bar", "baz"]
print (second) // ["foo", "bar", "hello"]
print (third) // ["foo", "qux", "baz"]
print (fourth) // ["foo", "qux", "baz", "hoge", "hello"]