Is this macro possible?

I would like to create a Macro that takes an existing class and applies that to an empty class to create a read-only backed version of that class. I have not had any luck figuring out how to expand the class passed to the macro to determine what variables it has. Is this even possible ?

        """
        public class KeywordObject {
            var id: Int = 0
            var word:String = ""
        }

        @Backing<KeywordObject>
        public class Keyword {
        }
        """,
        expandedSource: """
        public class Keyword {
            private var backing: KeywordObject
            let id: Int
            let word: String

            init(backing:KeywordObject) {
                self.id = backing.id
                self.word = backing.word
                self.backing = backing
            }
        }
        """,

It wouldn't work because an attached macro is only given the declaration it's applied to, so it can't see the contents of KeywordObject.

You would have to do this as a macro attached to KeywordObject which generates the Keyword class definition rather than as a macro attached to Keyword.

There's potentially a solution here which uses @dynamicMemberLookup on the Keyword type to replicate the API surface of KeywordObject, and then only provides a get in order to give a read-only interface to the backing object? This would have the downside that you wouldn't be copying the values out of backing so if backing was having its properties changed behind the scenes you'd still observe those changes thru Keyword.

1 Like

I looked into that and learned a lot from this discussion.

but stalled when I hit this.

It appears this is now broken in Xcode 15 Beta 3 if names are added to the global scope. Protocols for automated mocks, etc. of course are a compelling use case for this.

Error: 'peer' macros are not allowed to introduce arbitrary names at global scope

Yes I need readonly copies.