Accessor macros for properties with initial values

I'm trying to write a macro that will replace a stored property with a computed property similar to how the Observable macro works. But I can't get this to work for properties that define initial values. I have something like this:

extension Foo {
	@Bar static let someFoo = Foo()
}

Which I want to translate into something like this:

extension Foo {
	static var someFoo: Foo {
		// some extra logic here
		return _someFoo
	}
	
	private static var _someFoo = Foo()
}

However, it seems like the annotated property can only be modified in the specific ways that the macro system allows. So I can add the private stored property, and I can add an accessor to the original property, but the property remains as it was written, so I end up with this:

extension Foo {
	static let someFoo = Foo() {
		// some extra logic here
		return _someFoo
	}
	
	private static var _someFoo = Foo()
}

Which is invalid because the computed property is a let and has an initial value.

I could require writing var instead (though I'd prefer to keep using let), but I'd still need to somehow replace the initial value with a type annotation.

Am I overlooking something? How does the Observable macro accomplish this?

Isn’t this the exact thing that property wrappers are for? I don’t see why you’d need a full-fledged macro for this.

The particular use case I have involves generating a string based on the name of the property which is why I'm using a macro. But your comment made me realize that I should be able to accomplish what I'm trying to do by using a macro to apply a property wrapper, so thanks for the suggestion!

I'm still curious about the original question though. I took a closer look at the proposal, and it has this to say about accessor macros:

A side effect of the expansion is to remove any initializer from the stored property itself; it is up to the implementation of the accessor macro to either diagnose the presence of the initializer (if it cannot be used) or incorporate it in the result.

Now I'm wondering if there's a bug, because I don't actually see the initializer being removed from the property.

4 Likes

For everyone coming across this issue via search engines:
There has already been filed a bug report on GitHub apple/swift (#63731)
See here: GitHub Issue 63731 on apple/swift

1 Like