The forbidding of circular dependencies is exactly what makes it hard to achieve parallelism! It means you have to draw nice clean module boundaries and split your compilation units there. Clean boundaries sound nice, except… what if the module is getting large? Can you just take half the module, ctrl-x, ctrl-v into a new file, and get faster compilation times without having to do any massive refactors?
In C, usually yes.
In C++, sometimes yes. It depends on how template-heavy the code is, but if you have some discipline you can keep most logic out of headers and thus easily splittable.
In Rust, almost always no, because of circular dependencies. You can try to work around it by adding `dyn Trait` everywhere, but that requires a lot of code changes and comes at big ergonomic costs (and a small runtime cost).
Which is why in practice, Rust compilation units are almost always larger than C++ or C compilation units. Rust can sometimes be competitive with C++ on compilation speed anyway, thanks to a smarter build system and not having to re-parse headers a billion times, but usually it's slower.
The industry accepted way of handling circular dependencies is to not have them and heavily lint against them in languages which permit them in compilation or runtime.
> Can you just take half the module, ctrl-x, ctrl-v into a new file, and get faster compilation times without having to do any massive refactors?…In Rust, almost always no, because of circular dependencies
This feels like a strange, overly-specific complaint. It reads a bit like “When I write entangled code, it’s hard to untangle”. Like, yeah, the only thing that’ll save you from that is…not writing entangled code? I’m not of the opinion that the argument of “yeah but C lets me do whacky stuff” is a particularly strong line.
FWIW, letting a module grow, and then splitting modules up by cut-and-pasting stuff out along natural domain lines generally _is_ how I write Rust. Largely due to how easy it makes it to construct modules and submodules.