1

When creating an identifier in a declarative macro, it is mandatory to put additional brackets in the macro (double brackets). I was wondering why the compiler does not just (always) add the additional brackets.

Example 1: this code will not compile because only single brackets are used where double brackets are mandatory:

macro_rules! some_macro {
    () => {
        let mut x = 1;

        x += 1;

        x
    };
}

fn main() {
    let y = some_macro!();
}

Adding double brackets solves the compile error.

Example 2: this code will compile regardless of using single or double brackets:

macro_rules! some_macro {
    () => {{
        1
    }};
}

fn main() {
    let y = some_macro!();
}

Are there cases in which a macro with double brackets breaks single brackets macros? If not, why doesn't the compiler always adds double brackets?

J. Doe
  • 12,159
  • 9
  • 60
  • 114

1 Answers1

5

There is a case where double braces would fail. Since the inside braces create a scope, if you want to declare any identifiers, they won't be "exported":

// compiles with single braces but not double braces
macro_rules! set_ident_to_1 {
    ($var: ident) => {
        let $var = 1;
    }
}

fn main() {
    set_ident_to_1!(foo);
    println!("{}", foo);
}

There may also be cases where braces just straight up aren't allowed, like top level definitions. Take, for example, this macro that crates a repetitive Deref implementation:

struct Foo {
    x: i32
}

struct Bar {
    y: u32
}

// compiles with single braces but not double braces
macro_rules! create_repetitive_impl {
    ($prop: ident, $typ: ty, $target: ty) => {
        impl std::ops::Deref for $typ {
            type Target = $target;
            
            fn deref(&self) -> &Self::Target {
                &self.$prop
            }
        }
    }
}

create_repetitive_impl!(x, Foo, i32);
create_repetitive_impl!(y, Bar, u32);

fn main() {
    println!("{:?}", Foo {x: 5}.checked_mul(6))
}
Aplet123
  • 33,825
  • 1
  • 29
  • 55