Macros defined with macro_rules!
have weird scoping. As I understand it, this is due to historical compiler limitations, and the compiler could support normal scoping now. I understand that there's some sort of effort to add a new macro construct that would not only fix scoping, but also do some other things, but I assume that's a long way away. Also, there could be reasons someone would want the old kind of macro definition, but the new scoping. I want to see if there's an appetite for a “quick fix” for the current scoping problems.
Background
Currently, there seem to be three patterns for the scoping for a macro_rules!
macro.
-
macro_rules! foo { … }
The macro is only available outside the module with
#[macro_use]
and doesn't have normal item scope at all. -
macro_rules! foo { … } pub(crate) use foo;
The macro gets normal item scope, but it's only visible within the crate and can't be made fully public (
pub use foo;
is an error). -
Publicly exported from the crate root:
#[macro_export] macro_rules! foo { … }
The macro gets normal item scope and is fully public, but it will be exported from the root of the crate. You can re-export it from the current module, but you can't hide the re-export.
I try very hard to keep my code clearly organised and well-documented. When writing macros, I want to group them together with related functions, types and constants in a module with an appropriate name, documentation and position in the hierarchy. But none of these options work well with that in mind:
- The
#[macro_use]
approach means you usually can't see where a macro comes from when reading a module that uses it. It does at least show up in the correct section of rustdoc output, but intra-doc links don't work. [EDIT: Actually they do work, but forward references require insertinguse
statements! More importantly, these show up with .] - The
pub(crate) use
approach means the macro will show up with (“restricted visibility”) in documentation, suggesting it shouldn't be used outside a narrow context, and it can't be used by other crates. - The
#[macro_export]
approach means the macro will show up in the crate root rather than an appropriate module when reading the rustdoc output, and IDEs will automatically insertuse
statements with the “wrong” path, which I can only catch with manual code review. It subverts my attempts to organise things into appropriate modules.
Proposal
What I'd really like is to be able to write:
pub macro_rules! foo {
…
}
The macro foo!
would be a public item with normal scoping, exported from the current module rather than the crate root.
If this specific syntax is doable, this would also provide an alternative to the weird pub(crate) use foo;
idiom:
pub(crate) macro_rules! foo {
…
}
But more than that, it would also work for any other visibility level you can express with pub(…)
, e.g. self
or super
. I'd probably use the latter quite a bit.
What do you think? Does anyone know if there's some technical limitation that would prevent this?