15

I would love to be able to something like the following:

macro_rules! impl_a_method(
    ($obj:ident, $body:block) => (
        fn a_method(foo: Foo, bar: Bar, baz: Baz) -> $obj $body
    )
)

// Implementation would look like:

impl_a_method!(MyType, {
    MyType {
        foo: foo.blah(),
        bar: bar.bloo(),
        baz: baz.floozy(),
    }
})

My real-world example features methods with much larger signatures which I have to implement in unique ways for 30+ different types.

I have tried something similar to the above macro, however I run into errors where rustc considers foo, bar and baz unresolved names at the expansion site (even though I'm sure the macro declaration lexically precedes the use).

Is it possible to do something like this?

If not, can you recommend an approach that would achieve something similar?

mindTree
  • 916
  • 9
  • 18

1 Answers1

11

That's not possible due to macro hygiene. Any identifier introduced in the macro body is guaranteed to be different from any identifier at the macro call site. You have to provide all identifiers yourself, which somewhat defies the purpose of the macro:

impl_a_method!(MyType, (foo, bar, baz), {
    MyType {
        foo: foo.blah(),
        bar: bar.bloo(),
        baz: baz.floozy(),
    }
})

This is done by this macro:

macro_rules! impl_a_method(
    ($obj:ty, ($_foo:ident, $_bar:ident, $_baz:ident), $body:expr) => (
        fn a_method($_foo: Foo, $_bar: Bar, $_baz: Baz) -> $obj { $body }
    )
)

The only thing you're really saving here is writing types of method parameters.

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • 11
    "macro hygiene" is actually a pretty well-defined idea: https://en.wikipedia.org/wiki/Hygienic_macro – solidsnack Apr 16 '17 at 07:57
  • 1
    In Julia there is the function `esc` which makes introduced symbols be as-is and not be transformed to unique names (gensymed). Is there no such thing in Rust? – Post Self Jan 12 '20 at 18:00
  • @PostSelf I don't think there is - the only way to get an unescaped identifier is to pass it externally. I believe this is done on purpose. – Vladimir Matveev Jan 14 '20 at 17:55
  • I would love to know if this is at least possible with proc macros? I have tried writing one and it doesn't seem to work but I don't know if it's just because I'm doing something wrong. hygiene shouldn't be an obstacle for a prog macro since they aren't hygienic in general. – Joseph Garvin Jul 22 '20 at 00:39