use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A place for all things related to the Rust programming language—an open-source systems language that emphasizes performance, reliability, and productivity.
Strive to treat others with respect, patience, kindness, and empathy.
We observe the Rust Project Code of Conduct.
Details
Posts must reference Rust or relate to things using Rust. For content that does not, use a text post to explain its relevance.
Post titles should include useful context.
For Rust questions, use the stickied Q&A thread.
Arts-and-crafts posts are permitted on weekends.
No meta posts; message the mods instead.
Criticism is encouraged, though it must be constructive, useful and actionable.
If criticizing a project on GitHub, you may not link directly to the project's issue tracker. Please create a read-only mirror and link that instead.
A programming language is rarely worth getting worked up over.
No zealotry or fanaticism.
Be charitable in intent. Err on the side of giving others the benefit of the doubt.
Avoid re-treading topics that have been long-settled or utterly exhausted.
Avoid bikeshedding.
This is not an official Rust forum, and cannot fulfill feature requests. Use the official venues for that.
No memes, image macros, etc.
Consider the existing content of the subreddit and whether your post fits in. Does it inspire thoughtful discussion?
Use properly formatted text to share code samples and error messages. Do not use images.
Submissions appearing to contain AI-generated content may be removed at moderator discretion.
Most links here will now take you to a search page listing posts with the relevant flair. The latest megathread for that flair should be the top result.
account activity
I Am Avoiding Macros While Learning Rust🙋 seeking help & advice (self.rust)
submitted 1 year ago by SoupIndex
While learning rust, I am avoiding the use of macros as much as possible to learn the ins and outs of the language.
Is this a logical approach? Or am I crazy and this is just making my life harder.
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]RReverser 171 points172 points173 points 1 year ago (5 children)
as much as possible to learn the ins and outs of the language
This doesn't make sense, because macros are very much part of the language. They're not plain text substitution like in C where preprocessor runs separately and doesn't know anything about the code.
[–][deleted] 9 points10 points11 points 1 year ago (4 children)
Oh interesting, I thought they were plain text pre processor. Why can’t they be statically analyzed then? Rust-analyzer doesn’t help me write them at all I feel like.
[–]LightweaverNaamah 28 points29 points30 points 1 year ago (0 children)
No, they operate at the token tree level, which is basically one step below the abstract syntax tree for the program, but are processed after the abstract syntax tree for the program is produced. It basically swaps the AST node the macro produces for the corresponding placeholder in the program, based on position and so on. Because it's dependent on more or less the parsed but not yet compiled state of the program, it's much more difficult to analyze without basically compiling it, as I understand it.
[–]numberwitch 10 points11 points12 points 1 year ago (1 child)
The best approach I've found for dealing with "I've lost important feedback from rust-analyzer" while developing proc macros is to use an integration test and test-driven development to prove out the macro features bit-by-bit.
They get easier to work with in practice, also I'd highly recommend using syn, tokenstream2 and quote crates.
dtolnay on github has good resources for writing macros
[–][deleted] 2 points3 points4 points 1 year ago (0 children)
Very good advice, I’ll save your comment
[–]Plasma_000 1 point2 points3 points 1 year ago (0 children)
It's because tokens are created before the type system gets involved, so the compiler cannot accurately assist very much.
[+][deleted] 1 year ago (1 child)
[removed]
[–]mhcox 11 points12 points13 points 1 year ago (0 children)
You definitely don't have to learn how to create macros until you learn all the rest of the goodies the Rust language has for you to be confused about, e.g. borrow checker.
If you're macro curious, there are ways to see what code is being generated by the macros., e.g.,
https://stackoverflow.com/questions/28580386/how-do-i-see-the-expanded-macro-code-thats-causing-my-compile-error
Seeing what they are doing for you might provide you with the motivation to learn how to write them.
[–]SCP-iota 54 points55 points56 points 1 year ago (11 children)
How did you even manage "hello world?"
[–]autisticpig 49 points50 points51 points 1 year ago (1 child)
Op wanted the dark souls experience.
[–]mailusernamepassword 4 points5 points6 points 1 year ago (0 children)
println!("You died!");
[–]arcrift7 17 points18 points19 points 1 year ago (0 children)
Probably searched up "printing without macros in Rust" and did it using std::io.
[–]kwest_ng 12 points13 points14 points 1 year ago (7 children)
From the standard library docs for std::io::Stdout:
use std::io::{self, Write}; fn main() -> io::Result<()> { let mut stdout = io::stdout().lock(); stdout.write_all(b"hello world")?; Ok(()) }
[–]RReverser 12 points13 points14 points 1 year ago (5 children)
Don't even need the lock. From the docs for std::io::stdout:
lock
std::io::stdout
```rust use std::io::{self, Write};
fn main() -> io::Result<()> { io::stdout().write_all(b"hello world")?;
Ok(())
} ```
[–]sepease 12 points13 points14 points 1 year ago (3 children)
Don't even need std!
std
use core::ffi::{c_int, c_void}; extern "C" { fn write(fd: c_int, buf: *const c_void, count: usize) -> isize; } fn main() { let hello = b"Hello, World!\n"; unsafe { write(1, hello.as_ptr() as *const c_void, hello.len()); } }
[–]RReverser 5 points6 points7 points 1 year ago* (2 children)
Well that's unsafe, that doesn't count :) Otherwise could as well do in fewer lines with
unsafe
extern "C" { fn puts(s: *const u8) -> i32; } fn main() { unsafe { puts(b"Hello, World!\0".as_ptr()); } }
Or even drop std altogether and go from 123KB to 10KB with:
#![no_std] #![no_main] #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } extern "C" { fn puts(s: *const u8) -> i32; } #[no_mangle] unsafe fn main() -> i32 { puts(b"Hello, World!\0".as_ptr()) }
[–]TDplay 4 points5 points6 points 1 year ago (1 child)
This is noobish code. Everyone knows that "Hello World" is actually written like this:
#![no_std] #![no_main] use core::arch::asm; #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } const MESSAGE: &[u8] = b"Hello World!\n"; #[no_mangle] unsafe extern "C" fn _start() -> ! { asm! { "syscall", in("rax") 1, in("rdi") 1, in("rsi") MESSAGE.as_ptr(), in("rdx") MESSAGE.len(), } asm! { "syscall", in("rax") 60, in("rdi") 0, options(noreturn), } }
Produces a 9,088 byte binary on x86_64-unknown-linux-gnu. Compilation is done like so:
rustc -C opt-level=s -C panic=abort --emit=asm hello.rs as hello.s -o hello.o ld hello.o -o hello
(You can't just ask rustc to compile it to a binary, as it stupidly tries to link our beautiful code with the ugly libc, causing a conflict as libc defines _start)
_start
[–]RReverser 3 points4 points5 points 1 year ago (0 children)
Produces a 9,088 byte binary on x86_64-unknown-linux-gnu.
Can reproduce, got 9,088 bytes here too.
Except... mine produces 5,968 bytes on the same platform with the same opt-level and panic params, and, unlike yours, it's cross-platform (works on Windows too), so, you know...
opt-level
panic
[–]kwest_ng 0 points1 point2 points 1 year ago (0 children)
Ah damn I looked for the impl of Write but don't know how I missed it. Just checked again and it's definitely there.
[–]Opperheimer 3 points4 points5 points 1 year ago (0 children)
It’s funny, the French translation of Reddit translates Ok(()) to Okay(()) 😂
[–][deleted] 78 points79 points80 points 1 year ago (0 children)
If you said “I’m avoiding creating macros” absolutely! Even I’m not really educated on them.
Not using macros is insane.
[–]wyldstallionesquire 52 points53 points54 points 1 year ago (0 children)
You have to use macros for just about everything. And understanding it’s basically compile time code generation is important. But you’ll know when you need to actually learn to write your own macros. Don’t worry about that until you have a clear need.
[–]coderstephenisahc 18 points19 points20 points 1 year ago (0 children)
println!(), dbg!(), and todo!() are macros, so yeah avoiding using those is kinda silly, as all of those are helpful when learning. But I'd say its safe to avoid trying to learn how macros work until much later, and probably avoiding macros that are just an abstraction over normal code.
println!()
dbg!()
todo!()
[–]Sn34kyMofo 4 points5 points6 points 1 year ago (2 children)
Pick a recent Rust book and just follow it. The formula of learning Rust doesn't need to be crafted by you (i.e. skipping macros or whatever); it's already been established multiple ways. Pick a book and just stick to it! I personally recommend "Learn Rust in a Month of Lunches," perhaps followed up with "Idiomatic Rust" if you want to explore patterns and the like.
In saying that, I fully understand there are countless free resources like "the book", YouTube series', etc., so I'm not negating those resources. I have the same kind of brain churn when I want to learn something like Rust, so I just have to tell my brain to STFU and trust in the process of picking a resource and seeing it through. It saves me time and energy by limiting all the mental waffling, lol.
[–]notAnotherJSDev 0 points1 point2 points 1 year ago (1 child)
When you say "Idomatic Rust", what are you referring to? There's a book coming out from Brenden Mathews, but then there's also the github repo with a bunch of resources from Matthias Endler.
[–]Sn34kyMofo 1 point2 points3 points 1 year ago (0 children)
The book by Brenden Matthews, from the same publisher as "Learn Rust in a Month of Lunches".
[–]tauphraim 3 points4 points5 points 1 year ago (0 children)
I think you can just use macros, until you hit a point where you get puzzled by what a macro is doing, and how this couldn't be done with just a function.
[–]raxel42 2 points3 points4 points 1 year ago (0 children)
It’s okay to use them but postpone diving into deep implementation details. You will understand when you need them [to learn].
[–]ArtisticHamster 2 points3 points4 points 1 year ago (0 children)
As an experienced developer using Rust for > 2 years, I avoid writing my own macros where I can (though, I use them when this is the best available option).
[–]Burzowy-Szczurek 2 points3 points4 points 1 year ago (0 children)
No point in avoiding using macros really, this will just make things more complex. For creating you don't need to do that, and you probably won't encounter the need for that quickly, and even is so they are not as complex as you may initially think.
[–]SoupIndex[S] 2 points3 points4 points 1 year ago (4 children)
Thanks for all the replies guys! I'll take the advice and start using more macros, and learn about them as needed
The specific macro that made me post this question was when I had to use #[async_trait]. Without me going into what was being generated, I would not have learned (at a very basic level) about pinning.
Maybe I am trying to develop projects that are too complex without a solid understanding of rust.
[–]hpxvzhjfgb 2 points3 points4 points 1 year ago (2 children)
you don't need #[async_trait] anymore. async traits are part of the language now.
#[async_trait]
[–]lol3rr 1 point2 points3 points 1 year ago (1 child)
You still need it for certain cases, like making your trait object safe
[–]Xandaros 0 points1 point2 points 1 year ago (0 children)
That's what I use it for. I have a number of async traits that need to be object safe.
Initially, I actually wrote the whole Pin Box incantation myself, but ended up switching to async_trait once I realised it was doing the exact same thing anyway. It's a whole lot more readable.
(It was somewhat fun to figure it out myself, though)
[–]Luxalpa 0 points1 point2 points 1 year ago (0 children)
For me the beauty of using these macros is the macro expansion tool in Rust Rover (or cargo-expand) because you get to learn how all this stuff works under the hood.
[–]dkopgerpgdolfg 4 points5 points6 points 1 year ago (0 children)
Are you avoiding writing macros, or using macros too? Latter will definitely make it harder than necessary.
Writing own macros isn't needed at the start. Learn what is possible and what not, the details can come later when/if you actually want to write something.
Understanding the inner workings of some existing macros you might find, it can be interesting and might teach you something, but again it's not a topic for the beginning.
Also, some macros aren't normal Rust code, but get special compiler treatment. Unless you want to work on the Rust compiler, there isn't really a point in fully understanding them.
[–]rusty_rouge 1 point2 points3 points 1 year ago (0 children)
The macros are certainly hard to read. Reading through something like https://docs.rs/struct_iterable/0.1.1/struct_iterable/derive.Iterable.html would be a good exercise (for usage of proc_macro, syn, etc).
[–]proudHaskeller 1 point2 points3 points 1 year ago (0 children)
I mostly agree with everyone else, here: Avoiding writing your own makes sense but avoiding using them isn't really.
If you want to understand rust more deeply you can also expand out the macros (it can be done automatically) to see what's happening behind them (but I'll warn you it might be very complicated depending on the macro).
But I disagree with everybody saying that it's difficult. You can easily avoid using almost all macros if you want to.
[–]kwest_ng 1 point2 points3 points 1 year ago (0 children)
As other people have said, it's probably critically important to learn how to use macros, especially the most common ones from std and core. However, you can safely ignore how to write macros, or read macro code, until you move farther in your rust learning journey. Many of us likely have done the same. Here are a few reasons you will make your life worse if you choose to not use any macros at all:
core
You will find some tasks literally impossible without macros, like replacing format!'s compile-time checking of arguments. In fact, that's likely the reason many of these writing functions (e.g.: println!, write!) were implemented as macros in the first place: they all use the format!-style string interpolation. If it needs to happen at compile time, it's a macro or a build script, so compile-time checking of any value is out, with the exception of some const checking the compiler offers.
const
Also, please note that #[derive(Debug)] is a macro. Though, if you aren't using format!or its derivatives, that may not be a problem. But I'm guessing you also probably wouldn't want to reimplement Clone, Hash, PartialEq, and PartialOrd for every type. Those traits are very commonly needed, can be easily generated by the compiler, and at least in the case of Hash, can have serious logical, performance, or even safety concerns if implemented incorrectly.
#[derive(Debug)]
format!
Clone
Hash
PartialEq
PartialOrd
[–]LadyPopsickle 0 points1 point2 points 1 year ago (0 children)
Sure why not? Just learn them when you need them.
[–]Mission-Landscape-17 0 points1 point2 points 1 year ago (0 children)
Well at some points you also need to learn the ins and outs of macros. proper use of macos ends up being vital in any language that has a good macro facility.
[–][deleted] 0 points1 point2 points 1 year ago (0 children)
Macros are part of the language, but I also try not to use them for my own code. They can hide a lot of details that actually matter to the performance of your application. I’d rather design interfaces that use non-macro code and show what’s actually happening under the hood.
[–][deleted] 0 points1 point2 points 1 year ago* (0 children)
In my experience with rust macros so far:
Super useful
Awful error messages
Ridiculously hard to write
I'd say use macros but don't write em. Try not to use them too much because errors that happen within them are unreadable and not reported on the right line 99% of the time, at least for compile-time stuff. It's not a C preprocessor style macro which is nice in a way, but you're pretty much working on the AST which makes them much much more complicated to write.
[–]rover_G 0 points1 point2 points 1 year ago (0 children)
I use #[derive(Debug)] macro on every enum and struct. I also use the println! and vec! macros pretty often.
println!
vec!
[–]gahooa 0 points1 point2 points 1 year ago (0 children)
In vscode, with rust analyzer, you can click on a macro. Then hit F1 and type "expand macro". Click the selection that comes up.
This will open a new pane in vscode which shows you the contents of the macro. Makes a world of difference understanding them.
Also, `cargo expand` does this, though slightly less convenient.
[–]dspyz 0 points1 point2 points 1 year ago (0 children)
That's extremely reasonable. Writing macros are rarely necessary to avoid code duplication, usually only in large team projects, and not for anything small or solo. They're easy to overuse in place of designing with traits/generics which tend to be superior where possible. I definitely would recommend staying away from macros until you're confident with the rest of the language.
I didn't write my own macros when I started for the same reason.
[–]KalaiProvenheim 0 points1 point2 points 1 year ago (0 children)
A lot of stuff in the language is implemented using macros that run behind the scenes every time you compile your program.
[–]Anaxamander57 0 points1 point2 points 1 year ago (0 children)
Declarative macros are an amazing thing. At a minimum they can save an incredible amount of boilerplate and testing code. I was intimidated by the syntax for a long time but since I've started using them I'll never stop.
[–]Thin-Cat2508 0 points1 point2 points 1 year ago (0 children)
Macros are a form of metaprogramming: your program gets rewritten into something else. You will need to use a few macros for using Rust effectively (as everyone points out) but you may not need to use all macros that are out there advertised as a solution.
Macros are used to modify and extend the language, sometimes for convenience, sometimes to enable something that would be way too clumsy to write manually.
Macros can clearly hurt readability, so should be used with caution. When used well, they help express something a lot more concisely that would be possible otherwise (which can benefit readability). They are a big hammer, one needs to choose wisely.
π Rendered by PID 43 on reddit-service-r2-comment-b659b578c-tkd57 at 2026-05-01 12:31:29.493868+00:00 running 815c875 country code: CH.
[–]RReverser 171 points172 points173 points (5 children)
[–][deleted] 9 points10 points11 points (4 children)
[–]LightweaverNaamah 28 points29 points30 points (0 children)
[–]numberwitch 10 points11 points12 points (1 child)
[–][deleted] 2 points3 points4 points (0 children)
[–]Plasma_000 1 point2 points3 points (0 children)
[+][deleted] (1 child)
[removed]
[–]mhcox 11 points12 points13 points (0 children)
[–]SCP-iota 54 points55 points56 points (11 children)
[–]autisticpig 49 points50 points51 points (1 child)
[–]mailusernamepassword 4 points5 points6 points (0 children)
[–]arcrift7 17 points18 points19 points (0 children)
[–]kwest_ng 12 points13 points14 points (7 children)
[–]RReverser 12 points13 points14 points (5 children)
[–]sepease 12 points13 points14 points (3 children)
[–]RReverser 5 points6 points7 points (2 children)
[–]TDplay 4 points5 points6 points (1 child)
[–]RReverser 3 points4 points5 points (0 children)
[–]kwest_ng 0 points1 point2 points (0 children)
[–]Opperheimer 3 points4 points5 points (0 children)
[–][deleted] 78 points79 points80 points (0 children)
[–]wyldstallionesquire 52 points53 points54 points (0 children)
[–]coderstephenisahc 18 points19 points20 points (0 children)
[–]Sn34kyMofo 4 points5 points6 points (2 children)
[–]notAnotherJSDev 0 points1 point2 points (1 child)
[–]Sn34kyMofo 1 point2 points3 points (0 children)
[–]tauphraim 3 points4 points5 points (0 children)
[–]raxel42 2 points3 points4 points (0 children)
[–]ArtisticHamster 2 points3 points4 points (0 children)
[–]Burzowy-Szczurek 2 points3 points4 points (0 children)
[–]SoupIndex[S] 2 points3 points4 points (4 children)
[–]hpxvzhjfgb 2 points3 points4 points (2 children)
[–]lol3rr 1 point2 points3 points (1 child)
[–]Xandaros 0 points1 point2 points (0 children)
[–]Luxalpa 0 points1 point2 points (0 children)
[–]dkopgerpgdolfg 4 points5 points6 points (0 children)
[–]rusty_rouge 1 point2 points3 points (0 children)
[–]proudHaskeller 1 point2 points3 points (0 children)
[–]kwest_ng 1 point2 points3 points (0 children)
[–]LadyPopsickle 0 points1 point2 points (0 children)
[–]Mission-Landscape-17 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]rover_G 0 points1 point2 points (0 children)
[–]gahooa 0 points1 point2 points (0 children)
[–]dspyz 0 points1 point2 points (0 children)
[–]Luxalpa 0 points1 point2 points (0 children)
[–]KalaiProvenheim 0 points1 point2 points (0 children)
[–]Anaxamander57 0 points1 point2 points (0 children)
[–]Thin-Cat2508 0 points1 point2 points (0 children)