Postfix macro syntax for methods via opt-in attribute: obj.method!(...) → obj.method(MACRO!(...))
Nobody has claimed this yet.
- Dominant language
- Markdown
- Stars
- 6.6k
- Forks
- 1.7k
- Avg merge
- 16h 14m
- Merged PRs (30d)
- 1
Description
I’d like to propose a small but meaningful ergonomic improvement that bridges Rust’s powerful macro system with its object-oriented method syntax—without blurring their responsibilities.
The idea is simple: allow a method to be annotated with #[postfix_macro(M)], so that calling obj.method!(args...) automatically expands to obj.method(M!(args...)) at parse time.
Crucially:
- The macro
Mremains a completely ordinary, free-standing macro. It could beformat_args!,serde_json::json!, or any user-defined macro. It is not tied to the type, doesn’t need special awareness ofself, and can be used anywhere else in the codebase. - The method remains a normal Rust method: it has a regular signature, shows up in documentation, can be called directly (e.g.,
logger.info(my_preformatted_args)), and contains all the real logic—like checking log levels, writing to a buffer, or validating state.
In other words: the macro handles compile-time argument preprocessing; the method handles runtime behavior. They stay separate in definition, but combine naturally at the call site.
Why does this matter? Consider logging:
// Today
info!(logger, "user {} connected", name);
// With this proposal
logger.info!("user {} connected", name);
The second version reads more fluently because the action (info!) is attached to its context (logger). Yet under the hood, nothing magical happens: it’s just logger.info(format_args!(...)).
This pattern applies beyond logging—to serialization (obj.serialize!( { x: 1 } )), validation, GPU kernels, and more. All these cases share the same structure: a macro processes arguments at compile time, and a method acts on them at runtime.
How this differs from RFC #2442
This is not a revival of RFC #2442 ("Postfix macros"), which proposed allowing any macro to be called in postfix position (e.g., expr.any_macro!(...)). That approach was rightly rejected because it:
- Created ambiguity between methods and macros;
- Allowed arbitrary macros to “attach” to any type without the type author’s consent;
- Risked namespace pollution and hidden coupling.
In contrast, this proposal is explicit, opt-in, and scoped:
- Only methods explicitly annotated with
#[postfix_macro]gain the!syntax; - The macro is chosen by the type author, not the caller;
- No new naming rules or resolution semantics are introduced.
It’s less about “postfix macros” and more about giving method authors a way to offer a macro-powered shorthand—while keeping full control.
Safety & minimalism
- Fully backward compatible;
- Requires only a parser-level desugaring (like
?); - Zero runtime cost;
- No changes to Rust’s macro or trait systems.
This isn’t about making macros “look like methods.”
It’s about letting each do what it’s best at—and compose them cleanly where it matters most: in user code.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading RFC #2442 and the proposed #[postfix_macro(M)] expansion described in this issue. The issue names no implementation files, tests, or entry points; done would require an accepted design that specifies the syntax, opt-in behavior, macro resolution, and compatibility implications.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100