@attached(accessor) macro on let property - bug or a feature?

Hello everyone,

While working with @attached(accessor) macros, i discovered that it's currently possible to apply such macros to let properties on a type to generate and then use get accessors on such properties.

@attached(accessor, names: named(get))
public macro Computed() = #externalMacro(module: "ComputedMacros", type: "ComputedMacro")
...
public struct ComputedMacro: AccessorMacro {
    public static func expansion(
        of node: AttributeSyntax,
        providingAccessorsOf declaration: some DeclSyntaxProtocol,
        in context: some MacroExpansionContext
    ) throws -> [AccessorDeclSyntax] {
        [
            """
            get { "Vakhid" }
            """
        ]
    }
}
...
struct Person {
    @Computed
    let name: String
}

let person = Person()

print(person.name) // "Vakhid"

This is also true for the latest swift and swift-syntax snapshot (swift-DEVELOPMENT-SNAPSHOT-2024-05-15-a).

After doing some research, i found the following threads on the topic:

After going through each of them, i couldn't arrive to a decisive conclusion whether such behaviour of @attached(accessor) macros is a bug or a feature.

Specifically i am confused, because:

  • Taking into account that @propertyWrapper are not allowed on let properties, it would be logic to assume that @attached(accessor) macros aren't as well.

  • Compiler disallows accessors on let properties, but this is not the case when an accessor is generated by an @attached(accessor) macro, as can be seen in the above example.

  • There is a pitch for allowing @attached(accessor) macros on let declarations, but the following comment by @ahoppen on swift-syntax repo sounds like current behaviour is something that could potentially stay:

Disallowing getters on let might be guarded behind the Swift 6 language mode. But I won’t be alone in deciding that.

Could you please help clarifying this. Many thanks in advance :pray:

cc: @amritpan @Douglas_Gregor

1 Like

My understanding (from [AccessorMacro] 'let' declarations cannot be computed properties · Issue #2491 · apple/swift-syntax · GitHub) was that the let accessor "works" for now but will go away someday.

2 Likes

The ability to specify accessors on let variables is a bug in the compiler and should not be allowed.

5 Likes

Thank you very much for clarification.

To draw a parallel, how do property observers work on stored properties annotated with @attached(accessor) macros that convert those stored properties into computed properties ?

For example, given

@Observable
final class Counter {
    var value: Int = 0 {
        didSet {
            print(oldValue)
        }
        willSet {
            print(newValue)
        }
    }
}

that expands to

@Observable
final class Counter {
    ...
    @ObservationTracked
    var value: Int = 0 {
        @storageRestrictions(initializes: _value)
        init(initialValue) {
            _value = initialValue
        }
        get {
            access(keyPath: \.value)
            return _value
        }
        set {
            withMutation(keyPath: \.value) {
                _value = newValue
            }
        }
        didSet {
            print(oldValue)
        }
        willSet {
            print(newValue)
        }
    }
    ...
}

why doesn't compiler generate an error 'didSet' / 'willSet' cannot be provided together with a getter, same as when such program is written manually ?