Circumvent Immutability in Struct (Partial Application of COW)
I am trying to find a way to be able to mutate a member of a struct from an immutable context. I need to be able to have some sort of identifier that differentiates between a copy of an instance and the initial instance.
struct Foo {
// Need to update this value when there are multiple references to it from an immutable context
var id = ID()
class ID {
init() { }
}
func doSomethingAndUpdateID() {
if (!isKnownUniquelyReferenced(&id)) {
// Need to assign new instance of `ID` to `id` despite immutable context.
id = ID()
}
// do something
}
}
var a = Foo()
var b = a
b.doSomethingAndUpdateID()
// I need to the following to be false:
a.id === b.id
Despite the immutable context of doSomethingAndUpdateID, I need to be able to change the value of id so I can differentiate between a and b despite the fact that neither of them are mutated. My initial thought was to put the id property inside of a Box class, but this does not work either because the reference of the boxed type is shared between a and b, so changing the inner value of the boxed type changes it for both a and b. My next thought was that maybe there is a way to do this sort of thing with unsafe operations, but I have no idea how to use those types or even if it can be done with them.
I basically want to provide the normal copy-on-write semantics and mutability behaviour to all members of Foo except for id. I want copies of Foo that have not been mutated to share references to all of their properties except id, thus having an identifier on Foo that ignores copy-on-write to differentiate between copies of an instance of Foo. This would essentially be a partial application of copy-on-write semantics. This entails copies being able to not share references to certain values.
Without understanding what you're trying to achieve, this question just reads as "How to mutate something guaranteed to be immutable". The simple answer is... you can't, and that's the whole point.
Why can't you just make doSomethingAndUpdateID a mutating func?
You can't (and shouldn't be able to) do that, not even with UnsafePointer. For all that the language is concerned, you're mutating b. Maybe you could make Foo a class? Especially since Foo seems to have some notion of Identity.
Unfortunately @Lantua, I need Foo to be a struct. This question stems from a problem I am having with a LinkedList type that is a struct. It has an id property that is checked whether or not it is uniquely referenced upon every mutation, and if it is not then it copies all the nodes of the linked list (this is done in every mutating function). Also, to ensure that indices are valid when subscripting, they store a weak reference to the id of their parent list. The problem I am facing is that even if a copy of an instance of the list is created, you cannot hold on to the indices taken from the copied list prior to being mutated but after being copied because upon mutating, the id of the linked list is changed and thus the indices cannot be used to access values in the list.
Because of this, calling swapAt(_:_:) from a generic context on a linked list fails because the second index has already been invalidated.
In that case, shouldn't updateID() be mutating. And since it only occurs only when LinkedList changes value (via subscript, etc), I don't see a problem of it being mutating func.