restermans
(Vakhid Betrakhmadov)
1
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 
cc: @amritpan @Douglas_Gregor
1 Like
vanvoorden
(Rick van Voorden)
2
2 Likes
ahoppen
(Alex Hoppen)
3
The ability to specify accessors on let variables is a bug in the compiler and should not be allowed.
5 Likes
restermans
(Vakhid Betrakhmadov)
4
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 ?