When can a macro return a value?

One can simply assign the value of the declarative macro vec![] back to a declared variable, e.g.

let v = vec![1, 2, 3];

We then expect v to be a vector of usize.

Let's take, as an example, a possible and incomplete implementation of one of the match arms of the macro vec![], like so:

( $( $x:expr ),* ) => {
    {
        let mut v = Vec::new();
        $( v.push($x); )*
        v
    }
};

We can see that whenever we call let v = vec![...]; // let LHS = RHS;, the RHS get expanded into something like that of the implementation above, one can imagine the expanded codes to look something like so:

let v = let mut v = Vec::new(); v.push(1); v.push(2); ...

Of course, let v = vec![1,2,3]; compiles well.

On the other hand, for procedural macros, the expanded codes on the RHS may SIMILARLY contain statements like let length_array = /*some calculations*/ within the expanded codes and it fails to compile as the RHS of the statement contains statements instead of expression (at least that is what Rust complains about).

Which is why when I am writing procedural macros that returns a value, I have to 'return' a 'hardcoded' token (computed at compile time) back E.g. https://github.com/jymchng/median-proc-macro/blob/master/crates/median-pm-core/src/implement.rs#L75

My question is, how are declarative macros expanded such that it is capable of returning a value to the macro caller while expanding the codes and yet why procedural macros cannot really do that?

No, there's an additional set of braces, which causes the macro to expand to a block expression:

let v = { let mut v = Vec::new(); v.push(1); v.push(2); ... v };

but I'm not sure exactly what you are misunderstanding, because you obviously wrote this code yourself, including the extra pair of braces (since the standard library's real vec![] impl is completely different, it simply forwards to Box<[T]>::into_vec()).

There is no difference between how the expansion of procedural and declarative macros is treated. If you make your procedural macro expand to a block, then it can be used in expression position as well.

4 Likes

Nice @H2CO3, indeed, I am missing the extra braces which is the cause of my confusion, thank you for clearing it up!

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.