Questions about new "macro" keyword and syntax


#1

IIRC there’s new macro surface syntax coming in Rust 1.31. Where would I be able to read up on how that interacts with the just-stabilized procedural macros?

That’s assuming they even interact, and that macro not simply a replacement for macro_rules! that can also do procedural macros…somehow.


Pre-release for 1.30
#2

Do you mean declarative macros? (As opposed to procedural.) I don’t see anything in https://github.com/rust-lang/rust/issues/39412 that indicates stabilization any time soon.


#3

See that’s the confusing part: the declarative macro facility seems to support a procedure-like form, aside from a pattern-matched, macro_rules!-like form.

What I’m after in this case is insight into the relation (if any) between the procedure-like macro form, and procedural macros (i.e. the feature stabilized in 1.30). If there’s no relation between the 2 then I’d like to know the purpose/motivation of the procedure-like macro form.

Indeed, there are a lot of unchecked boxes.


#4

I don’t know what this refers to, do you have a link that describes it?


#5

What I mean by that is that this seems to be supported:

macro m($i:ident) {
  // macro contents
}

Compare that to (the also supported):

macro m {
  ($i:ident) => {
    // macro contents
  }
  // any other arms here
}

#6

(Declarative macros 2.0 are) To eventually replace macro_rules! because it is an unhygenic hack and with other assorted historical mistakes.


#7

because it is an unhygenic

Can you explain the unhygeine of macro_rules! a bit more? Rust macros are often introduced as hygenic, and I haven’t seen unhygeine from them in practice.


#8

They are, but not for everything… for example:

macro_rules! m {
    () => { struct Foo; }
}

m!();
m!(); // Error... 

#9

So what would be the ideal semantics in this case? Would there no outside-visible struct Foo with ideal hygeine?


#10

That’s not a hygiene problem; it’s an important use-case for macros.

If you want an actual hygiene problem: generic type parameter names aren’t sanitised:

use std::fmt::Debug;

macro_rules! m {
    ($field:ident) => {
        fn method<T: Debug>(&self, v: &T) {
            println!("{:?}: {:?}", self.$field, v);
        }
    };
}

struct Struct<T> {
    prefix: T,
}

impl<T: Debug> Struct<T> {
    m!(prefix);
}

(Contrived, but I had this exact problem a while ago which I had to solve with long, unlikely-to-be-used generic parameter names.)


#11

I see the second form I provided above replacing macro_rules, and that is not surprising as its grammar is pretty similar to that of macro_rules (except for an annoying difference in how macro expansion body blocks are ended: with a semicolon vs a comma, that also behave differently in what usage they find correct).

In this thread I’m more concerned with the first syntactic form. Is that meant to become sugar for the just-stabilized proc-macro’s?

BTW, for an additional, real world macro problem I’ve run into is that macro’s can’t nicely define other macros that have some of their definition handed down to them by virtue of being defined by the first macro rather than simple argument passing (I’ll call these closure-like macros, as they’re analogous to closures in the general sense). That’s to say, they can define them, but not without leaking weird impl details to the top level macro, at the very least the $ sign in something like \$(...) * for matching multiplicities with kleene operators. While not a hygiene issue in the traditional symbol clash sense, I’d definitely call this a hygiene issue.


#12

The declaritive macro syntax

macro my_macro($name:ident) {
    // expands to
}

is just another way to declare pattern matching macros with only one arm. (Potentially they could give better errors than “no arm expected” based on only having one arm?)

IIRC, the format of decl_macro hasn’t gone through an RFC yet and merely exists to have something to experiment with declaritive macros 2.0 in.

(macro macros will replace macro_rules! macros when macros 2.0 becomes a thing in the far future.)


#13

Supported in Nightly but not stable, right? As @CAD97 said the syntax is not settled yet.

Either way, when you said “procedure-like” I was thinking of procedural macros that take and return a TokenStream, and run arbitrary code. This syntax may be somewhat similar to function definition syntax (with a name followed by parameters in a pair of parenthesis) but it is still definitely declarative: the expansion is // macro contents with simple substitution.


#14

Correct.

Yeah the single-match form is definitely declarative, but for all I knew it could have been sugar for proc_macros. Somehow. I just wasn’t sure.