One of the blockers of full hygiene is breaking it. While hygiene is nice, it is sometimes desired to define unhygienic identifiers, like in this example:
macro helper() {
struct HygieneOfUpper;
}
macro foo() {
helper!();
impl HygieneOfUpper {}
}
There are many different ways in which this would be used, so it needs to be quite flexible. In the example above, the HygieneOfUpper
would just be lift up one level to the hygiene of foo
. I have seen some ideas, like a lift!()
macro that can be wrapped around macro invocations to lift the hygiene of all identifiers defined in the nested macro.
But I have come up with an idea that would solve this problem in a much better way in my opinion.
with_hygiene!(hygiene, ident)
This solution would introduce a new compiler intrinsic macro (that could also be implemented as a proc macro in userland I think?) that defines a new identifier ident
with the hygiene of hygiene
.
It's defined like this
macro with_hygiene($hy:ident, $idents:tt) {
/* expands to $idents but with all idents getting the hygiene of $hy */
}
The above example would be rewritten as:
macro helper($hy:ident) {
with_hygiene!($hy, struct HygieneOfUpper);
}
macro foo() {
helper!(hy);
impl HygieneOfUpper {}
}
Advantages:
- quite elegant in my opinion
- extremely flexible
- implementable as a proc macro, (I think?) so not much magic
- the user of the macro must opt-in to hygiene breaking
Disadvantages:
- needing to introduce all these unused
$hy
idents as params - a macro, so a bit awkward to use
I quite like this idea though, but I think it could be improved still.
What is your opinion on it, do you think it would be feasible?