Not sure how the best way to do it would be, but it would be awesome to be able to disable macro hygiene.
macro_rules! test {
() => raw {
val = 42;
}
}
let mut val = 0;
test!();
// val = 3
This would be useful to create global macros that can still access local variables.
We should consider making you call the macro with two exclamation marks to really make sure you know you are calling a raw macro - though, you decide on that one. I'm personally against it.
Local macros can access local variables. You can do sth like:
macro_rules! test_raw {
($val:ident) => raw {
$val = 42;
}
}
fn foo() {
let mut val = 0;
macro_rules! test {
() => {
test_raw!(val);
};
}
test!();
// val = 3
}
This is what I do when I don't want to write val too much.
The current situation is fine IMO.
I usually do
macro_rules! make_test() {
($val:ident) => {
macro_rules! test() {
() => {
$val = 42;
}
}
}
}
fn foo() {
let mut val = 0;
make_test!(val);
test!();
// val = 3
}
So yeah, same thing. But still it would be better if you could just disable it completely.
I'm against it because it increases complexity of macros with no benefit (which cannot be achieved in other ways).
@legolord208,
Your example is very good.
You use macros like functions.
Global variables is an anti-pattern.
For macros without hygiene local variables are global.
In your example you pass the variables so it works.
While I agree to that argument, code can also become messier without it.
While I agree to that argument, code can also become messier without it.
Strongly disagree. Macros that change context without any hint about this - this is make code messier.
It is like functions that works global variables, but worst, because it changes not unique variable, but all with some name.
This is going to be done in macros 2.0 on per-identifier basis, e.g. like this:
macro test() {
#val = 42; // mark val as unhygienic
}
let mut val = 0;
test!();
assert_eq!(val, 42);
This is not implemented yet, but see some discussion in https://github.com/rust-lang/rust/pull/40847.
@petrochenkov is that really the final conclusion? How is that any better from the current macro system? Through the messaging, I've thought hygienic macros were something that Rust does better than other languages, not something it should be ashamed of?
@est31
is that really the final conclusion?
No :)
But it's a likely course of action.
Macros 2.0 (macro) as currently implemented show how useless fully hygienic macros are. You can't even generate an item visible outside of the macro! Some kind of opt-out is necessary.
@petrochenkov from how I read the discussion, breaking hygiene this way is not meant to be supported. E.g. the PR description explicitly says that the "Breaking Hygiene" section of the Racket macro hygiene system doesn't apply here. The uses of # that I could see in the discussion all concerned stuff being exported to be visible outside of the macro, so the rules got stricter, not less strict.
Note that I do support # being mandated for exporting stuff from a macro, but there should be no way to import stuff to a macro from the call site. Importing from the definition site, maybe with mandated #, is okay.
If they're already being discussed, I will happily close this issue. Thanks for the heads up, @petrochenkov :)
Most helpful comment
This is going to be done in macros 2.0 on per-identifier basis, e.g. like this:
This is not implemented yet, but see some discussion in https://github.com/rust-lang/rust/pull/40847.