Not effortlessly supporting composition (multiple such macros on a single function) seems like a major limitation to me. Take two of the given examples - @Logged
and @Traced
- that could very well be desired simultaneously. Along with countless other common wrapper patterns from Python, Java, etc, like @Backoff
, @Register
, @ReportExceptions
, @Cache
, @AuthRequired
, etc.
Would it be better to tackle these cases separately from actual body generation as in the @Remote
example?
If only one body generator were permitted at a time - and it took only a function declaration, not a definition - then that greatly simplifies that use-case. Being able to have an arbitrary number of nested wrappers can deal with most others. And the two compose perfectly well together.
Actually mutating the body is a third, orthogonal operation, I think. It raises way more and way more complicated questions regarding type-checking and all the rest that have been touched on already in this thread. (and I say that not as a compiler or macro author so much as a user, that has to have some intuition and comprehension of how the macros I use will actually behave)
I get the appeal of having fewer, more universal tools, but from the design of Swift macros so far it seems like there's no overwhelming desire to have few macro types - if there were, it'd inevitably trend towards a single type of macro which can arbitrarily modify the entire program's AST. I appreciate the benefits of having distinct types of macros that elegantly solve specific subsets of the compile-time code generation / mutation space.
Plus, nothing prevents a "one function modifier macro type to rule them all" from being added later and superseding prior, more focused macro types. If and when all the challenges around it are figured out (and perhaps, only after seeing that more narrowly-purposed macro types aren't sufficient in practice).