lang (macros | syntax)
Declarative macros 2.0. A replacement for macro_rules!
. This is mostly a
placeholder RFC since many of the issues affecting the new macro system are
(or will be) addressed in other RFCs. This RFC may be expanded at a later date.
Currently in this RFC:
macro
).In other RFCs:
To come in separate RFCs:
Note this RFC does not involve procedural macros (aka syntax extensions).
There are several changes to the declarative macro system which are desirable but not backwards compatible (See RFC 1561 for some changes to macro naming and modularisation, I would also like to propose improvements to hygiene in macros, and some improved syntax).
In order to maintain Rust's backwards compatibility guarantees, we cannot change
the existing system (macro_rules!
) to accommodate these changes. I therefore
propose a new declarative macro system to live alongside macro_rules!
.
Example (possible) improvements:
// Naming (RFC 1561)
fn main() {
a::foo!(...);
}
mod a {
// Macro privacy (TBA)
pub macro foo { ... }
}
// Relative paths (part of hygiene reform, TBA)
mod a {
pub macro foo { ... bar() ... }
fn bar() { ... }
}
fn main() {
a::foo!(...); // Expansion calls a::bar
}
// Syntax (TBA)
macro foo($a: ident) => {
return $a + 1;
}
I believe it is extremely important that moving to the new macro system is as straightforward as possible for both macro users and authors. This must be the case so that users make the transition to the new system and we are not left with two systems forever.
A goal of this design is that for macro users, there is no difference in using the two systems other than how macros are named. For macro authors, most macros that work in the old system should work in the new system with minimal changes. Macros which will need some adjustment are those that exploit holes in the current hygiene system.
There will be a new system of declarative macros using similar syntax and
semantics to the current macro_rules!
system.
A declarative macro is declared using the macro
keyword. For example, where a
macro foo
is declared today as macro_rules! foo { ... }
, it will be declared
using macro foo { ... }
. I leave the syntax of the macro body for later
specification.
Throughout this RFC, I use 'declarative macro' to refer to a macro declared
using declarative (and domain specific) syntax (such as the current
macro_rules!
syntax). The 'declarative macros' name is in opposition to
'procedural macros', which are declared as Rust programs. The specific
declarative syntax using pattern matching and templating is often referred to as
'macros by example'.
'Pattern macro' has been suggested as an alternative for 'declarative macro'.
There is a risk that macro_rules!
is good enough for most users and there is
low adoption of the new system. Possibly worse would be that there is high
adoption but little migration from the old system, leading to us having to
support two systems forever.
Make backwards incompatible changes to macro_rules!
. This is probably a
non-starter due to our stability guarantees. We might be able to make something
work if this was considered desirable.
Limit ourselves to backwards compatible changes to macro_rules!
. I don't think
this is worthwhile. It's not clear we can make meaningful improvements without
breaking backwards compatibility.
Use macro!
instead of macro
(proposed in an earlier version of this RFC).
Don't use a keyword - either make macro
not a keyword or use a different word
for declarative macros.
Live with the existing system.
What to do with macro_rules
? We will need to maintain it at least until macro
is stable. Hopefully, we can then deprecate it (some time will be required to
migrate users to the new system). Eventually, I hope we can remove macro_rules!
.
That will take a long time, and would require a 2.0 version of Rust to strictly
adhere to our stability guarantees.