{
    "slug": "rust_macro_system",
    "term": "Rust Macro System",
    "category": "rust",
    "difficulty": "advanced",
    "short": "Rust macros generate code at compile time through declarative pattern matching or procedural token manipulation, not runtime text substitution.",
    "long": "Rust has two distinct macro systems that both run during compilation, expanding into ordinary Rust code before type checking and code generation. They are nothing like C's textual preprocessor: Rust macros operate on token streams and respect the language's syntax and hygiene rules, so they cannot silently capture or clobber identifiers from the call site.\n\nDeclarative macros, written with `macro_rules!`, match against patterns of tokens and emit code per matching arm. They use fragment specifiers such as `$x:expr`, `$t:ty`, `$i:ident`, and `$p:pat` to capture syntactic categories, and repetition operators like `$( ... )*` and `$( ... ),+` to handle variadic input. The standard library's `vec!`, `println!`, and `assert_eq!` are declarative macros. They are powerful for reducing boilerplate but are limited to pattern-driven expansion and can produce confusing errors when input does not match any arm.\n\nProcedural macros are functions that take a `TokenStream` and return a `TokenStream`, giving full programmatic control over generated code. They come in three forms: derive macros (`#[derive(Serialize)]`), attribute macros (`#[route(GET, \"/\")]`), and function-like macros (`sql!(...)`). Procedural macros must live in their own crate marked with `proc-macro = true`, and the ecosystem relies on the `syn` crate to parse tokens into an AST and `quote` to build output, with `proc-macro2` bridging the types.\n\nHygiene is the feature that separates Rust macros from naive substitution. Identifiers introduced by a macro live in their own syntactic context, so a temporary variable a macro creates will not collide with a variable of the same name at the call site. This makes macros composable and safe in ways textual macros never are.\n\nMacros are the right tool when you need code that varies in structure - implementing a trait for many types, building a domain-specific syntax, or eliminating repetitive impl blocks. They are the wrong tool when a generic function, trait, or const would do, because macros are harder to read, harder to debug (errors point at expanded code), slower to compile, and invisible to many IDE features. Reach for the simplest abstraction first and escalate to macros only when ordinary language features cannot express the pattern.",
    "aliases": [
        "macro_rules",
        "proc macros",
        "derive macro",
        "declarative macros"
    ],
    "tags": [
        "rust",
        "macros",
        "metaprogramming",
        "code-generation",
        "macro-rules",
        "procedural-macros"
    ],
    "misconception": "Rust macros are textual find-and-replace like the C preprocessor and can leak or capture variables from the surrounding scope. In reality they operate on typed token streams with hygiene, so macro-introduced identifiers cannot accidentally collide with call-site names.",
    "why_it_matters": "Reaching for macros where a generic or trait would suffice produces code that is slow to compile, hard to debug, and opaque to tooling, while misunderstanding hygiene leads to surprising expansion failures.",
    "common_mistakes": [
        "Writing a macro_rules! macro for something a generic function or trait could express, adding complexity for no real benefit.",
        "Assuming macros substitute text like the C preprocessor and expecting them to capture or shadow call-site variables.",
        "Forgetting that procedural macros must live in a separate crate with proc-macro = true in Cargo.toml.",
        "Choosing the wrong fragment specifier (for example $x:expr where $x:ty is needed) and getting cryptic match failures.",
        "Mishandling repetition syntax so $( ... )* expands with the wrong separators or arity."
    ],
    "when_to_use": [
        "Generating repetitive trait implementations across many types where generics cannot abstract the variation.",
        "Building variadic or DSL-like syntax such as vec!, format strings, or query builders.",
        "Deriving boilerplate like serialization or builders via derive macros instead of hand-writing each impl.",
        "Eliminating structural duplication that no function, generic, or const expression can capture."
    ],
    "avoid_when": [
        "A generic function, trait, or const can express the same behavior with clearer errors and better tooling support.",
        "The abstraction is needed only once and the macro adds indirection that obscures rather than clarifies the code.",
        "You are duplicating logic that could be shared through ordinary composition, since macro-generated code is harder to debug.",
        "Compile time and readability matter more than saving a few lines, because macros expand slowly and confuse IDEs."
    ],
    "related": [
        "rust_traits",
        "rust_pattern_matching",
        "code_duplication_types"
    ],
    "prerequisites": [
        "rust_pattern_matching",
        "rust_traits"
    ],
    "refs": [
        "https://doc.rust-lang.org/book/ch19-06-macros.html",
        "https://doc.rust-lang.org/reference/macros-by-example.html",
        "https://doc.rust-lang.org/reference/procedural-macros.html",
        "https://veykril.github.io/tlborm/"
    ],
    "bad_code": "// Using a macro to do what a generic function does cleanly.\nmacro_rules! max_of {\n    ($a:expr, $b:expr) => {\n        // Evaluates each argument twice: side effects run twice!\n        if $a > $b { $a } else { $b }\n    };\n}\n\nfn next() -> i32 {\n    println!(\"called\");\n    5\n}\n\nfn main() {\n    // next() is invoked twice because the macro inlines the expression.\n    let m = max_of!(next(), 3);\n    println!(\"{}\", m);\n}",
    "good_code": "// A generic function: arguments evaluated once, clear errors, IDE-friendly.\nfn max_of<T: PartialOrd>(a: T, b: T) -> T {\n    if a > b { a } else { b }\n}\n\n// Reserve macros for what functions cannot do, e.g. variadic construction.\nmacro_rules! string_vec {\n    ( $( $item:expr ),* $(,)? ) => {\n        vec![ $( $item.to_string() ),* ]\n    };\n}\n\nfn next() -> i32 {\n    println!(\"called\");\n    5\n}\n\nfn main() {\n    // next() runs exactly once.\n    let m = max_of(next(), 3);\n    println!(\"{}\", m);\n\n    let names = string_vec![\"a\", \"b\", \"c\"];\n    println!(\"{:?}\", names);\n}",
    "quick_fix": "Prefer generics, traits, or const functions first; use macro_rules! only for variadic or structural code, and put procedural macros in a dedicated proc-macro crate with syn and quote.",
    "severity": "low",
    "effort": "medium",
    "created": "2026-06-06",
    "updated": "2026-06-06",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/rust_macro_system",
        "html_url": "https://codeclaritylab.com/glossary/rust_macro_system",
        "json_url": "https://codeclaritylab.com/glossary/rust_macro_system.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Rust Macro System](https://codeclaritylab.com/glossary/rust_macro_system) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/rust_macro_system"
            }
        }
    }
}