Rust macros in few sentences

Adeoti AyodejiAdeoti Ayodeji
3 min read

So, you've been writing Rust for a few days or so; or even a few weeks or months, or years, or decades. But! you've heard macros and have been burning to know what it's all about.

Claimers and disclaimers

What this article is about

It just explains what macros are in Rust with a few references

What this article is not about

It does not:

  • Teach you how to create macros or how to use them
  • Lead you to a blissful world of Rust including the use of macros
  • Contain expressive code examples of macros

Let's go

Macros are simply a feature of Rust (if not the most powerful) that allows you to write code that writes other code. I'll show you what I mean:

So, let's say I wanted to write a code that ensure that when invoked on an expression or assignment or statement, would print "Hello world" before the operation is carried out; I can write a special function that would insert the line for "Hello world" in a safe place within that expression, assignment or statement. Code example in pseudocode (why? because it will take long for me to explain the actual code in Rust and I'm sure you read the Disclaimer section):

# define a macro
macro_rules hello_world (thing: expression, assignment or statement) -> Valid_Code {
    var final_code = Valid_Code();
    final_code.append('print("Hello, World!")');
    final_code.append(thing);
    return final_code.to_valid_code();
}

Then I can use my macro like so:

hello_world!(
    add(4, 8)
)

and it will print "Hello, World!" before executing the code.

You get the concept?

Now if you've got pretty good eye, you'll say "That exclamation mark after hello_world is familiar, cos I've used it to pipe content to stdout using println!". Yeah, that's because println! is a macro...

But then...

Actually, there are two types of macros you'll see:

Declarative macros

This macro tends to match against patterns and replace the code you've dropped with other code. An example of this macro is the vec! macro.

Procedural macros

These macros (there are three types of them) are more magical and tend to accept some code as an input, operate on that code, and produce some code as an output (as quoted from the Rust book). They are the ones you impose on structs like #[derive()] or the #[tokio::main] we use when using the Actix framework.

Hoping your imaginations are as wild as Abraham the Mage in The Secrets of the Immortal (very nice book I'm reading), you'll begin to see limitless ways macros can be used.

You can literally add any feature to structs, add methods to structs, attributes and so on. You can make work easier for people when using piece of functionality like they did when Graydon's boys gave we Rustaceans vector = vec![1, 2, 3, 4] to use instead of:

let vector = Vec::new();
vector.push(1);
vector.push(2);
vector.push(3);
vector.push(4);

Where else can I see macros?

They are everywhere. From that #[derive()] syntax you see to the println! you tend to use instead of an actual debugger. The Rust Book talks more extensively about macros and you'll learn to use them more and creating them by reading that book. You can also read The Little Book of Rust Macros to shit yourself on macros.

Thank you

Do this by liking and sharing this article with your handsome and beautiful friends.

Best in inclusion

Yeah, I know the "bold of me to assume people define friends with articles such as 'handsome' and 'beautiful'". I was hoping to use a compliment_someone! macro there, but you'll need to read the link I put up there to understand it.

San kyo :fire

11
Subscribe to my newsletter

Read articles from Adeoti Ayodeji directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Adeoti Ayodeji
Adeoti Ayodeji

Software engineer, attracted to complex things by nature; passionate about Rust.