Property Wrapper didSet/willSet is ignored

Property wrappers are stored properties, so I expected didSet/willSet to work as usual, but they are ignored actually. Here is a short example:

@propertyWrapper
struct MutableWrapper<Value> {
   
  var wrappedValue: Value
  var projectedValue: Self {
    get { self }
    set { self = newValue }  
  }

  mutating func mutate() {
    // any mutations here
  }
}

struct TestStruct {

  @MutableWrapper var value = 0 {
     didSet { print("mutated") }
  }
}

func testDidSet() {
   var testStruct = TestStruct()
   testStruct.$value.mutate() // prints nothing
   testStruct.value = 1 // prints nothing
}

All sets are mutating; I don't use classes, so it's definitely a bug. Does anybody know something about it?
I really need to observe mutations of my wrapper itself. I didn't expect any problems here, especially since the compiler allowed me to write didSet under the wrapped value.

For me (Swift 5.10 Xcode 15.3), using XCTestCase and your exact code:

testStruct.value = 1 // prints "mutated"

I don't know how to observe mutations on the wrapper other than maybe creating a custom type for it.

import XCTest

extension Int {
  mutating func mutate() {
    self = 42
  }
}

@propertyWrapper
struct MutableWrapper<Value: BinaryInteger> {
   
  var wrappedValue: Value
  var projectedValue: Int = 0 {
    didSet {
      print("Mutated")
    }
  }
}

struct TestStruct {

  @MutableWrapper var value = 0 {
     didSet { print("mutated") }
  }
}

final class ActorDemoTests: XCTestCase {

  func testDidSet() {
     var testStruct = TestStruct()
     testStruct.$value.mutate() // prints Mutated
     testStruct.value = 1 // prints mutated
  }
}

Sorry if that isn't much help, though.

1 Like