5 ms·
The thing with rust is that you get safety with slow compilation, it's a tradeoff. Zig doesn't have the same safety guarantees, it's on the dev to use safe cod
by hoppp 2mo ago
The thing with rust is that you get safety with slow compilation, it's a tradeoff.
Zig doesn't have the same safety guarantees, it's on the dev to use safe coding patterns, so the tradeoff for safety is discipline or experience.
- steveklabnik 2mo agoRust's safety checks have basically nothing to do with its slow compile times. This is something that sounds intuitive but is just completely incorrect. In particular, Rust made several good design decisions around this stuff that keeps those checks fast, like keeping checks local rather than being global.
- jamiejquinn 2mo agoThat's interesting. Coming from C++ and Zig, the massive time "wasters" are metaprogramming features, i.e. Templates and comptime. Are Rust's macros the compile-time culprits?
- steveklabnik 2mo agoMacros can be, but in part because they can produce new items (top level declarations, to sort of make the same handwave as the article does) and so that means you have to do macro expansion and stuff before you can even start to check some things, and similar issues. See the link I posted above for some details on a related issue. There's also stuff around name resolution. Proc macros are just an inherently very slow way to do what they do. Because Rust commits to the traditional compilation model and pipleine (which I think is overall a good thing, or at least, a good thing to support), it does a lot of work that will eventually be thrown away. Consider this example: I have a library with a function foo that returns a simple 42. I have a binary which calls foo from that library and prints the result. Now imagine the library is a hundred thousand lines of unrelated code to what the binary needs, but is useful for other people. Because compilation works in the "produce libraries, produce binary, link them all together" style model, you have to compile the entire library with all of that code, when all you need is really one function. That intermediate work is useful, and I'm picking an example that's deliberately extreme, of course. There's a bunch of stuff like this, and I do not have time to really say more than that right now. But yeah, monomorphized generics also produce a lot of compile time pressure too, in various ways. Anyway I just also want to reiterate a few things: first of all, all of these decisions were made for good reasons, and there are pros to what Rust does and why. It's just that compile times suffer because of it. What I wish was that we had taken compile times into more consideration when deciding what to do and why in a more serious way. The same decisions might have been made, but at least it would have been known, rather than the situation now, where there's just a tremendous amount of work to try to optimize what exists, rather than having the freedom to maybe tweak some things to make that job way easier.
- saghm 2mo ago> Because Rust commits to the traditional compilation model and pipleine (which I think is overall a good thing, or at least, a good thing to support), it does a lot of work that will eventually be thrown away. Consider this example: I have a library with a function foo that returns a simple 42. I have a binary which calls foo from that library and prints the result. Now imagine the library is a hundred thousand lines of unrelated code to what the binary needs, but is useful for other people. Because compilation works in the "produce libraries, produce binary, link them all together" style model, you have to compile the entire library with all of that code, when all you need is really one function. That intermediate work is useful, and I'm picking an example that's deliberately extreme, of course. I feel extremely validated reading this! I've had a pet theory for a while that compile times would be drastically reduced if every single item in a crate were implicitly under a cargo feature flag and then they only got enabled if they were imported (and used in non-dead code). I know that making something like that work isn't anywhere close to as simple as I'm describing it, and there are probably a million edge cases, but I've long felt that the ergonomics of Cargo features basically making it too annoying to expose everything conditionally (and then transitively expose all of the features from all of the direct dependencies as well so that things depending on your library could also only conditionally enable them) is secretly the reason that people think Rust compile times are slow, and seeing someone who has way more direct knowledge than me of how all of it works under the hood give a similar take makes me more confident that I might have been on to something all along.
- steveklabnik 2mo agoYes, this idea is sort of similar, just like, more complicated in a sense than the clean design, which is what Zig does. Incidentally, you might want to look at gc-sections, which Rust already does. As well as https://rust-lang.github.io/rust-project-goals/2025h2/relink-dont-rebuild.html https://rust-lang.github.io/rust-project-goals/2025h2/relink... which is kinda related. The sort of key here is understanding that "produce a library" means that every public item is "used" in the sense of "do we need to compile it." The real trick is to do demand-driven compilation starting from the actual final program's needs, and this is inherently at odds with the idea of producing standalone libraries and combining them into the final artifact.
- pjmlp 2mo agoYet that doesn't prevent C++ to have REPL and hot reloading tools, use binary libraries instead of compiling the world from scratch, all of which allow for a much better experience.
- norman784 2mo agoThe issue with Rust proc macros is that they are impure, so even with incremental compilation, you need to expand them every time.
- afdbcreid 2mo agoThat's only part of the issue. First, declarative macros are of course pure. Most procedural macros are pure too, although there are exceptions (an infamous case is sqlx). And while rustc does expand them every time (although a config for declaring "my macro is pure" was considered multiple times and the teams generally view it favorably), rust-analyzer just declares "we don't support impure macros" and caches them anyway.
- stock_toaster 2mo ago(tongue in cheek) It seems recent history has shown that zig can get you to working software faster, then you can port it to rust once you are acquired or find market fit? Maybe at some point in the future zig could add a rust compilation target ( like with `-ofmt=c` )...
- chaz72 2mo agoI know this is mostly a joke but I have seriously wondered if “no hidden behavior” made it easier to port from Zig. Like, regardless of how easy or successful the port was in general, I think Zig’s explicitness may have worked in its favor.
- dnautics 2mo agojust staple a borrow checker to zig. it seems pretty doable as per my experiments