Property wrappers in Sendable classes

Hi there,

When I try and use Property Wrappers in a Sendable class, I get the error: "Stored property '_name' of 'Sendable'-conforming class 'Foo' is mutable; this is an error in the Swift 6 language mode".

Sample code:

@propertyWrapper struct Uppercase {
    private var str: String

    var wrappedValue: String {
        get { str }
        set { self.str = str.uppercased() }
    }

    init(wrappedValue: String) {
        self.str = wrappedValue.uppercased()
    }
}

final public class Foo: Sendable {
    @Uppercase var name = "Matt"
}

This error makes total sense, however, I wondered if there is any way (or any future proposal) to allow a property wrapper to be created with a constant synthesized wrapper variable?

i.e. rather than generate the wrapper as:

var _name: UpperCase

instead generate:

let _name: UpperCase

Without something like this, I imagine property wrappers are completely unusable in Swift 6 for Sendable classes.

Thanks!

Matt

4 Likes

Yeah this is an interesting one. I’d like to see it improved as well.

I’m not sure what state it is in currently, but I think this is the relevant pitch: [Pitch] Allow Accessor Macros on Let Declarations

1 Like

Just to add to this post, I realised my example above was invalid for other reasons.

I've rewritten it to demonstrate the point better...

import Foundation
import os

@propertyWrapper final class Uppercase: Sendable {
    private let str: OSAllocatedUnfairLock<String>

    var wrappedValue: String {
        get { str.withLock { $0 } }
        set { str.withLock { $0 = newValue.uppercased() } }
    }

    init(wrappedValue: String) {
        self.str = .init(initialState: wrappedValue.uppercased())
    }
}

final public class Foo: Sendable {

    // This compiles fine ok
    let _name = Uppercase(wrappedValue: "Matt")
    var name: String {
        get { _name.wrappedValue }
        set { _name.wrappedValue = newValue }
    }

    // This doesn't compile because the synthesized _name is mutable
    @Uppercase var surname = "Holgate"

}

(also worth adding that I know that this is sort of an anti-pattern for locking in property wrappers, but it's kind of valid for the case I am using I think).