RFC: macro functions

Borrow checker transparency. The simple

fn foo_mut(&mut self) -> &mut Foo { &mut self.foo }
fn bar_mut(&mut self) -> &mut Bar { &mut self.bar }

functions don't use any traits, but has an issue that you can't call both of them at the same time, since the first call would mutably borrow self. At the same time, using both &mut self.foo and &mut self.bar simultaneously is perfectly fine, because the borrow checker knows that the fields are disjoint. A macro function could pass that information to the call site, without explicitly exposing fields.

Is there any design of macros 2.0 anywhere? The tracking issue doesn't contain anything which could be called "design of new macro system", and afaik it doesn't exist anywhere. It's just a bag of internal tricks in the compiler.

Regardless, the use cases are overlapping but different. Macro functions are not expected to cover all possible uses of macros. They can't use custom syntax, they can't generate types or patterns or arbitrary code, but on the other hand they give stronger semantic guarantees than macros.

I don't know what's "unexpected" to you. I'd say recursive macros do something extremely complicated and hard to analyze, even if one can claim they do "expected" things. For example, in the field projection RFC it was mentioned that one of the motivations is that the declarative macro in the pin-project-lite crate is very unreadable.

I'd say quote! macro counts as surprising. At the surface layer it's Rust syntax, but it really isn't, it's just a sequence of tokens. The bodies of branches are simple, but the macro as a whole is absolutely not.

Even if you can claim that absolutely most macro transcribers are really valid Rust (which may well be true), it doesn't help you much in practice. Macros don't respect normal symbol visibility. Looking at the macro definitions, you have no idea what the symbols will resolve to. They will be resolved in the caller's context, and that may be a feature. One may claim that all types mentioned in macros should be fully qualified and all method calls should instead use the explicit UFC syntax, but that's not how most macros are usually written. And again, it doesn't tell you much, because even "absolute paths" in macros may in practice resolve to anything, depending on which crate was imported with the given root name.

From a static analysis standpoint, there is literally nothing you can claim about macros. You can try to make educated guesses, which will be right more or less often depending on the boldness of your guesses and on your empiric data, but there's nothing you can actually prove.

Would be, if we were designing macros from scratch. But we aren't, and there is too much code that will be broken if we try to retrofit it onto an existing system. We can add them to macros 2.0, but at this point it's a wild guess whether macros 2.0 or macro function would be implemented and stabilized first.

7 Likes