9 ms·
I have a hunch that rusts global compilation model (as opposed to C++ separate compilation, as crippled as it is in practice due to header-only libs and link ti
by choeger 4y ago
I have a hunch that rusts global compilation model (as opposed to C++ separate compilation, as crippled as it is in practice due to header-only libs and link times) should always lead to C++ scaling better with the size of the project.
Simply put: Rust doesn't offer an abstraction past type checking. Rust could potentially introduce its equivalent of PCH, or maybe it already does so in some internal cache, but as long as it uses monomorphization and no PhD student comes up with a clever trick to combine that with separate compilation it will scale worse.
That being said, maybe a more fair comparison wouldn't involve polymorphism in the rust code? C++ doesn't really have polymorphism, it uses templates for a similar feature. So what happens if someone replaces rusts polymorphic functions with macros?
- jimbob45 4y agoWhat do you mean by abstraction beyond type checking? I’m asking to educate myself.
- choeger 4y ago"Beyond" in the sense of "after". Languages that support separate compilation usually have some sort of artifacts that do not need to be type-checked anymore. Say, you compile an Ocaml module. The result is a compiled (bytecode or native code) file that represents the implementation of the module and doesn't need to be generated ever again. Essentially, the compiler abstracts over a module after it dealt with it. You could the If you do the same in rust, you need access to the module's implementation for monomorphization. You might skip the type checking of a function of the implementation or even cache the generated code for a monomorphization as optimizations, but generally you have to treat every function as often as it is used. So the best rust could do is akin to C++ precompiled headers whereas a language like OCaml can simply compile every module exactly once. Note: OCaml pays for this elegance. Its uniform object representation is less efficient than what rust does. It's a trade-off that the rust designers consciously made, I think.
- scaredginger 4y agoWhat you've said here is mostly correct. The key part you've omitted is that monomorphization is opt-in. One could write Rust like C if they wanted to; they would have to be insane, but they could
- vegerot 4y ago“opt-in” in the sense that I could just multiple versions of my functions if I want to? Agreed!
- scaredginger 4y agoYeah, or accept a small runtime cost in exchange for a smaller binary
- winrid 4y agoWhat big Rust projects do is split things up into crates which can be compiled as individual units. still bigger than a single file, but it helps.
- strager 4y agoYup! And I evaluated some different crate structures: https://quick-lint-js.com/blog/cpp-vs-rust-build-times/#optimizing-rust-with-different-layouts https://quick-lint-js.com/blog/cpp-vs-rust-build-times/#opti...
- not_the_fda 4y agoWhat big c++ projects do is split things up into libs which can be linked as individual units. still bigger than a single file, but it helps.
- winrid 4y agoI think being snarky is against the rules? Also creating nested libs as separate compilation units is so difficult with cmake etc I rarely seen a large C++ project do this... it is much easier with Cargo.
- not_the_fda 4y agoCreating nested libs in cmake is trivial and is done all the time. I'm sorry I was a bit snarky. But the thing is that the Rust evangelists don't understand the domains and types of large scale projects that C++ is used in and how those systems are built. Yet the they come along and keep pushing for Rust without understanding why C++ developers aren't switching and wave their hands at the issues we have with Rust. Show me a successful multi million line Rust project. Maybe throw in a complex UI. Maybe some GPU computation.
- winrid 4y agoI wouldn't call myself a rust evangelist. I prefer Java because it's productive and I can finish projects in it and not have to touch them for years. FWIW Rust is great for high performance web services, not so much UI stuff. C++ would be better for that.
- vegerot 4y ago> maybe a more fair comparison wouldn't involve polymorphism in the rust code? I think using features of the language is fair game btw, don't C++ templates also use monomorphization? I agree C++'s implementation is "lower level" (from a compiler perspective) than Rust generics, but that's one of Rust's selling features
- choeger 4y agoTemplate specialization sometimes looks like monomorphization, but it is really a different thing. I would compare C++ templates more macros, as they tend to do way more (e.g., allow for overload resolution).
- scaredginger 4y agoPlease elaborate. I agree C++ templates are more flexible in what they do (SFINAE etc.), but Rust generics and C++ templates still both use monomorphization
- choeger 4y agoI wouldn't say that C++ templates use monomorphization, because there are no polymorphic functions to begin with. Monomorphization, as in "the standard FPL technique", comes after type checking. C++ template specialization precedes type checking. Of course one can redefine the meaning of "polymorphism" and "monomorphization" to fit C++, but then these words lose nearly all meaning.
- vegerot 4y agoTIL. Thanks! In my plebeian brain I just thought “monomorphization = static dispatch” / 0-cost abstraction (vs. just writing multiple versions of a function), which both Rust generics and C++ templates fall into. Now I see that “monomorphization” has a specific definition in FPL
- scaredginger 4y agoI'm not satisfied by your explanation here. What definition of 'polymorphism' are you using? Why would type checking need to precede monomorphisation? Additionally, how do C++ concepts fit into your beliefs?
- clappski 4y agoC++ has two types of polymorphism; - Templates (compile time), which are generic bits of code that are monomorphized over every combination of template parameters that they're used with. - Virtualization (runtime), classic OO style polymorphism with a VTable (I think this similar to Rust's dyn trait?).
- spoiler 4y agoI think they meant to say that neither templates (nor virtual classes) are quite up to the same level of polymorphism that Rust has. Ie Rust type checkes at definition, as opposed to copy-paste and hope for the best (wrgt templates) when trying to compile the code. In other words Cpp templates are closer to Rusts declarative macros than to Rust generics. Hopefully concepts make this better in Cpp.
- gpderetta 4y agoUnfortunately, the concepts we got in C++20 still do not allow for type checking definitions and there isn't a realistic path to get there. I still think that C++ templates are different than rust macros as they are not a separate pass from type checking.
- pjmlp 4y agoAs always in C++ world, there is a workaround with static analysis, which could give errors when template code reaches out to capabilities that aren't part of the concept definition. Either that, or switch to Circle I guess.
- gpderetta 4y agoDoes such a static analysis exist? I think the most realistic solution is to write an archetype class for each concept and instantiate each template with its relevant archetypes. Now can we automate writing archetypes from concepts (and viceversa)? Maybe in C++64 when we finally get static reflection.
- ChubbyGlasses 4y agoThis is pure speculation, but I suspect egregious use of proc macros in Rust also inflate compilation times a bit. Just speaking anecdotally, but removing proc macros in one of my hobby projects decreased clean build by about ten seconds. Definitely not a couple magnitudes like the author saw, but not unnoticeable either.
- strager 4y agoWere those proc macros that you wrote, or proc macros in third-party crates?
- ChubbyGlasses 4y agoMine were mostly third party crates like bitflags and thiserror. Not saying that's what was effecting your build times, I'm not really familiar with your repo (my comment was only directed at my proj), but also it's pretty hard to write a significantly large project without macros; it's just the devil you kinda have to live with.
- dist1ll 4y agoProc macros are used too often in the Rust ecosystem, even for very simple crates. Library authors and maintainers care too little about compilation times.
- adwn 4y agoI always wonder: If the proc macros were executed JIT-like with the Cranelift backend instead of compiling them with the LLVM backend, wouldn't that drastically reduce build times of proc-macro-using code? The Rust compiler spends most of its time in LLVM, if I recall correctly.
- strager 4y agoI have heard talk of compiling proc macro crates with different rustc flags than other code. But I didn't go down this rabbit hole.