Using nonisolated with wrapped properties

Consider the following code:

struct W {
  var wrappedValue: Int { .zero }
  var projectedValue: Int { .max }

class C {
  @W nonisolated var value // error: 'nonisolated' is not supported on properties with property wrappers

  nonisolated func test() {
    _ = value // error: main actor-isolated property 'value' can not be referenced from a non-isolated context
    _ = $value // error: main actor-isolated property '$value' can not be referenced from a non-isolated context

The code currently fails to compile, because we do not support nonisolated on wrapped properties. This is because the accessors use the backing property (aka _value), which is a stored var so it would not be safe to mark it as nonisolated.

@hborla suggested to me that we could potentially allow this by making the backing property a stored let instead. In order to do that, we would need to provide users some way to spell it. One idea that came to my mind was letting users declared wrapped properties using a let, which would in turn making the backing property a let too.

Now, we currently don't allow placing let on computed properties in general, but I think perhaps we could allow it in this case, especially because the computed property transformation (and the backing property) is an implementation detail of property wrappers and when users write a wrapped property they look like a normal stored var rather than a computed property with explicit accessors. So letting users use a let in this context seems reasonable to me.

What do y'all think? I am really interested in hearing your thoughts and if you have any suggestions!


This seems to be consistent with wrapped function parameters, which are implicitly let (SE-0053) and use a let constant for their backing storage (SE-0293).

Would nonmutating setters on wrappedValue and projectedValue be disallowed? Does the distinction between "API-level" vs "implementation-detail" property wrappers have any relevance?