I read most of the gist, interesting approach. As someone who generally avoids macros like these but would like compile-time meta-programming, let me give you the perspective of the macro-averse (largely because I avoid domains that require boilerplate to begin with) who are going to be forced to deal with it in others' Swift code, from my experience in other languages.
-
Let me echo @willft and others in asking for a way to see the resulting source files after the macros have been expanded. For all C/C++'s faults, I can always check how their macros were used in
clang -many -flags -o foo.o
by runningclang -many -flags -E -o foo.i
and looking through the pre-processed file. This is a big deficiency in many modern macro systems. -
It is very important that all macro uses are carefully marked, ie there should always be a hash-prefixed symbol or something more glaring anywhere a macro is invoked. I don't think it's a good idea that the property wrapper example has none. Zig made a big mistake by reusing
if()
for statically known checks, as opposed to something more explicit likeif constexpr
(I'm aware that Zig can interpret the runtimeif
at compile-time, I'm talking about differentiating cases where you know the condition is statically known). -
Macros are an advanced feature, and requiring that those using it know internal compiler terminology is going to keep it so. It's good to keep it somewhat exclusive, but I wonder if that's the particular barrier to erect.
-
I don't use Rust but I've seen issues when cross-compiling it for Android, where flags that were only meant for Android were getting misapplied to the host macros. Something to avoid if taking a similar approach of compiling Swift macros for the host.