How to compose swift property wrappers?

There were some issues with using multiple property wrappers so that part of the feature was pulled out of Swift 5.1 but it will be available in 5.2. Until then you can’t use multiple property wrappers directly like this.


As of Swift 5.2, nested property wrappers have become a lot more stable, but they're still a bit difficult to work with. I've written an article here about it, but the trick is that since the outer wrapper's wrappedValue is the type of the inner wrapper, and the inner wrapper's wrappedValue is the direct property type, you have to make the wrapper operate on both types.

The basic idea I've followed is to create a protocol which the wrappers operate on. You can then have other wrappers conform to the protocol as well, in order to enable nesting.

For example, in the case of Doubled:

protocol Doublable {
    func doubling() -> Self
    func halving() -> Self
}

@propertyWrapper
struct Doubled<T: Doublable> {
    var number: T
    var wrappedValue: T {
        get { number.doubling() }
        set { number = newValue.halving() }
    }
    init(wrappedValue: T) {
        self.number = wrappedValue
    }
}

extension Int: Doublable {
    func doubling() -> Int {
        return self * 2
    }

    func halving() -> Int {
        return Int(self / 2)
    }
}

extension Doubled: Doublable {
    func doubling() -> Self {
        return Doubled(wrappedValue: self.wrappedValue)
    }

    func halving() -> Self {
        return Doubled(wrappedValue: self.wrappedValue)
    }
}

struct Test {
    @Doubled @Doubled var value: Int = 10
}

var test = Test()
print(test.value) // prints 40

You could do the same thing for Tripled, with a Tripleable protocol, and so on.

However, I should note that instead of nesting @Tripled @Doubled, it might be better to create another wrapper like @Multiple(6) instead: then you won't have to deal with any protocols, but you'll get the same effect.