Note on copy-on-write

1 minute read

Value types - Reference types

  • Value types, where each instance keeps a unique copy of its data, usually defined as a struct, enum, or tuple.
  • Reference types, where instances share a single copy of the data, and the type is usually defined as a class.

CoW - The value will be copied only upon mutation, and even then, only if it has more than one reference to it

  • Suppose we have 2 variables that reference to the same data.
  • DELAY the copy operation until they get a change.
  • Modify second variable, it will be copied and change so that only second variable is changed, first isn’t.
  • Not all value types have this behavior, have to implement it ourselves.
 1func address(_ object: UnsafeRawPointer) -> String {
 2    let address = Int(bitPattern: object)
 3    return NSString(format: "%p", address) as String
 4}
 5
 6struct Machine {
 7    var name: String
 8}
 9
10var a1 = Machine(name: "Refridge")
11var a2 = a1
12
13print(address(&a1)) // 0x10525f2d0
14print(address(&a2)) // 0x10525f2e0

Print DIFFERENT addresses!


Implement CoW

 1struct Machine {
 2    private final class MachineWrapper {
 3        var name: String
 4        init(_ name: String) {
 5            self.name = name
 6        }
 7    }
 8
 9    private var data: MachineWrapper
10
11    var name: String {
12        get { data.name }
13        set {
14            if !isKnownUniquelyReferenced(&data){
15                self.data = MachineWrapper(newValue)
16                print("Copied!!!")
17            } else {
18                self.data.name = newValue
19            }
20        }
21    }
22
23    init(name: String) {
24        data = MachineWrapper(name)
25    }
26}

Usage:

1var a1 = Machine(name: "Refridge")
2var a2 = a1
3
4a1.name = "Washing Machine"

Alright,

  • Machine is struct, so when assigning it to another variable, value is copied!
  • But the instance data inside is** a class**, so it is still SHARED by 2 copies UNTIL we modify the name of a1

More: