Hey all,
I want to write a property wrapper with a copy-on-write container and a mutating
method, and use it like this:
struct.$property.mutate()
I expected that it would be enough to use _modify
in the projectedValue
:
public var projectedValue: Self {
get { self }
_modify { yield &self }
}
The problem is that copy-on-write happens on every mutation. It looks like the Swift compiler generates the following property:
var $property: PropertyWrapper {
get { _property.projectedValue }
set { _property.projectedValue = newValue }
}
While I expect it to be:
var $property: PropertyWrapper {
get { _property.projectedValue }
_modify { yield _&property.projectedValue }
}
Is it the expected behavior or a bug in the compiler?
Purified example
Property wrapper:
@propertyWrapper
public struct PropertyWrapper {
public var projectedValue: Self {
get { self }
_modify { yield &self }
}
public var wrappedValue: Int {
get { box.value }
set { box.value = newValue }
}
private var box: Box
public init(wrappedValue: Int) {
self.box = Box(value: wrappedValue)
}
public mutating func needsCopyOnWrite() -> Bool {
!isKnownUniquelyReferenced(&box)
}
}
private final class Box {
var value: Int
init(value: Int) {
self.value = value
}
}
Usage:
struct Struct {
@PropertyWrapper
var property: Int
var propertyWrapper: PropertyWrapper {
get { _property.projectedValue }
_modify { yield &_property.projectedValue }
}
}
var s = Struct(property: 123)
print(s.$property.needsCopyOnWrite()) // true
print(s.propertyWrapper.needsCopyOnWrite()) // false
P.S. Why I need such property wrapper: to have a polymorphic property of a protocol type and to have a method for mutating the property specifying the concrete type in-place.
Artem