Macro hygiene only for expressions/variables but not for types?

Continuing the discussion from Helper closures which modify a state: Use RefCell or pass mutable references?:

(Playground)

Hmmm, I tried that too, but my naive approach didn't work at first (see Playground here).

I worked with macros previously which require a certain type to be in scope with a certain name, see radiorust::flt! or argmin::float! as two examples.

To give another example:

// We can define this macro outside `foo`:
macro_rules! works_on_type_T {
    () => { println!("{:?}", ::std::mem::size_of::<T>()); };
}

fn foo<T>(v: i32) {
    // But we must define this macro inside `foo`:
    macro_rules! works_on_variable_v {
        () => { println!("{:?}", ::std::mem::size_of_val(&v)); };
    }
    works_on_type_T!();
    works_on_variable_v!();
}

fn main() {
    foo::<u8>(12i32);
}

(Playground)

Why can I define works_on_type_T! outside foo (where T is not in scope) while works_on_variable_v! must be defined inside foo (where v is in scope).

Is this behavior intended? Why? Will it stay like this in future?

This came up recently here as well

Here's an excerpt from The Little Book of Rust Macros linked in that thread

macro_rules! macros in Rust are partially hygienic, also called mixed hygiene. Specifically, they are hygienic when it comes to local variables, labels and $crate, but nothing else.

My understanding is that it is intentional, but that it isn't necessarily going to be how macros work in declarative macros 2.0 (aka macro aka decl_macro aka macros-by-example). But also a lot of things are still up in the air on that feature so take that with a grain of salt.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.