Why is compilation time such a big deal for you?

the biggest thing is that writing rust is often error-message-driven, so to me the core thing I need to be fast-enough is that "you missed a comma", "you forgot a mut", "that's the wrong type", etc loop needs to be fast enough that I don't go check my phone while it's running

In Vim I use a plugin called coc-rust-analyzer. It gives these kinds of errors immediately when I save my file, without the need to compile. I'm pretty sure something like this will also exist for your editor of choice.

This way you don't need to compile your whole project to catch these small errors. :slight_smile:

Compiles times annoy me, but more than that, I think they cripple certain workflows.

Specifically, I've introduced Rust to several people who've all had large compile time complaints. In two particular cases, it boiled down to them having gotten used to a workflow that just doesn't work with Rust. Think about this TDD (test-driven development) workflow for writing new software:

  1. write tests for small portion of a feature
  2. implement that small portion of feature (15 line change max, preferably 3-5 lines)
  3. run tests (fix bugs, run tests again)
  4. repeat steps 1-3 maybe 20-50 times per hour

When writing JavaScript or Python, this cycle is 100% reasonable, and quite nice to use. You get immediate feedback, you get full tests for everything you're writing, and you get good feedback from the compiler. The whole cycle takes less than 5 minute for small additions. Swapping steps 1&2 is also reasonable.

When writing Rust, though, step 3 takes over a minute. Not even a 50% reduction in compile times would fix this: this workflow is impossible using Rust, and will be as long as we have a compiler which takes more than ~5 seconds on a large project. Something needs to change to make this workflow function - otherwise, you end up incredibly unproductive, writing 10 lines of code every 10 minutes. If you're used to thinking in terms of tests and getting that kind of immediate feedback on your logic, rust's compiles times can break your workflow in the worst way.

I've tried to help people I've introduced to rust by getting them to adopt slightly different workflows, but it can be a hard pill to swallow, especially if you've become invested in methodologies which support this kind of thing. The worst part is that several people who I've tried to talk into using Rust originally liked the idea for the exact same reason they like TDD: both make code more correct! So adopting Rust for it's correctness-focused design can be a lot less appealing if it means having to discard TDD, one of your best existing tools for making code correct.


With that said, I imagine a lot of new rustaceans can avoid this barrier - either because they come from C++, or because they don't have entrenched beliefs / habits. I personally learned Rust before I had strong opinions about any "right way" to write code, and so I formed my workflow around the Rust compiler. It usually ends up something like the following when writing new projects:

  1. plan & write a large batch of code, maybe about 5, 6 big functions
  2. check code (work out bugs from that one compilation, repeat until compiling)
  3. write 1-2 tests (run tests, work out bugs, repeat until well tested)
  4. repeat steps 1-3 once every 1-2 hours

I don't advocate for adopting this exact workflow, as it really isn't the best one. But I think that how much compile times matter to a person really does depend on that person's workflow, and I hope this comparison can give light to that. Compile times still annoy me, but they don't cripple my typical method of writing code.

13 Likes

Clearly there is going to be a lot of practices, habits, and opinions involved in this discussion.

Let me be a devil's advocate for a moment:

Test driven development is not a good way to produce correct code.

After all, tests can prove code wrong but they can never prove it correct. What one is actually doing with TDD is designing on the fly. It's part of that agile chaos. One has not yet worked out where one want's to go but one is going to proceed in whatever direction appeals at the moment. Makes one look productive at the time.

Those who want to deliver as correct code as possible, think safety critical systems, have Design Driven Development (DDD). There is a design, it is reviewed and approved, the code is derived from the design, the tests are independently derived from the design.

With more of a lean toward DDD the lengthy compile times of Rust become pretty much irrelevant. Compiling is only a small part of the job.

Don't get me wrong, I often cannot/will not work with such discipline. I too don't know where I want to go before I have tried to get there. I have not analysed my problem well. In the case of Rust I don't know it well enough to know if it will let me do what I want till I have done it.

But I feel Rust deserves, and rewards, a more DDD approach. More thinking up front and less hacking on the fly.

10 Likes

I'd argue that TDD can be done well, and can be a complement to a good design strategy rather than an antithesis against it. But I also agree that even if it did work well with rustc, it wouldn't really suite Rust as well.

When I've used TDD with JavaScript, about 3/4 of the bugs it catches are bugs which would never have compiled in Rust - incorrect function calls, typing errors, things which would have been caught by cargo check anyways. The other 1/4 are logic bugs which would have existed in Rust too - and not catching those is annoying. But they'll usually be caught by good testing later anyways.

I'd agree that a DDD approach can work super well, but I think you're discounting Rust's value in fast-paced environments. Think about Rust code thrown together without thought - if it compiles, it's still benefiting from Rust's type system and compile-time checks. And with those checks, it'll be almost painless to refactor into good code.

When I write a super hacky python script and then want a "good" version, I'm better off just rewriting it completely than trying to scrap any of the original code. But if I have similar Rust script, I can completely rearrange the code, do a few cargo check/fix cycles, and end up with something working. Rust code is so much more refactorable than other languages, I think the experience is almost incomparable.

Along those lines, I think that if we had top-tier compile times, Rust could excel at even more diverse fast-paced workflows that exist in other languages. Some of those workflows might not have full benefits in Rust, but allowing them anyway would remove a barrier for adopting Rust, and some likely would be super productive.

5 Likes

It is a big deal to me.

  • I have to think about compilation times, and adjust my projects and habits to reduce them (split into crates, keep caches around, etc.) That is unnecessary work, and I'd have a different workflow if compile times were much faster.

  • I have projects that take 30 minutes or longer to build in CI. This is a risk for me if something goes wrong and I need to release a quick fix. Quickest I can do is 30m, and if I don't get it right the first time, I'm looking at 1h or 1.5h of downtime!

18 Likes

That is my experience of programming in Javascript as well. Also Python.

In fact, with my other devil's hat on I have argued in the past that with good tests in place one should not rag on Javascript for not being a statically or strongly typed language. Your tests will catch those type errors and you should have good tests in place no matter what language you are using. Ergo, strong type checking is not required.

As it stands today I wear both devil's hats. I love Javascript in great part because it is not statically or strongly typed and I can just quickly hack stuff on the fly. On the other hand I love Rust for it's strict type and alias checking that make sure my code is lot less unreliable than usual. Make what you will of that state of mind :slight_smile:

I'm not yet convinced that putting together largish, non-trivial code that is correct and reliable is any slower in Rust than it is in Javascript. It's trading test and debug time vs compile speed.

2 Likes

Surely that is not unnecessary work. Such modularization is regarded as good practice in many places.

I don't follow. Surely one has built and tested the code before it's even on it's way to production? There should rarely be such downtime.

This is very interesting to me because my ~5 year career thus far has been almost all C++ and Javascript, but I've consistently found that the "red-green-refactor" TDD loop is completely infeasible on anything larger than a toy project. It's typically impossible to write a single meaningful test until I've done enough exploratory coding to make decisions about exactly what a test can or should be directly checking and what should be considered mere implementation details. I actively go out of my way to do TDD for changes that so perfectly fit our existing architecture and test suite that it actually can work, but even that only seems to happen at most once every few months, so in practice it's considered a novelty.

This is not to say anyone here is wrong. I have no idea if my experience or yours is the more statistically common one, much less the more statistically common one among projects that would be interested in a language like Rust for whatever reason. Maybe it's because I mostly work on frontend/UI code and you work on something very different. I mostly want to avoid anyone else getting the impression that every Javascripter expects a TDD workflow.

(unfortunately I've never had the opportunity to do any non-toy Rust work, so I can't speak directly to this topic, only on this slight tangent)

3 Likes

This is not the place to debate if TDD is worth it or not.

6 Likes

That is true.

Hence the various levels of tests. Unit tests at the bottom, functional tests, integration tests at the top.

At the unit test level the tests may well depend heavily on the actual implementation. You want to be exercising all the possible decisions and execution paths in the code. Which typically won't be know til the code is written.

Higher up one wants to test the functionality of the API. That it behaves as specified, no matter what the implementation details are. These tests can be derived from a specification rather that source code.

And so on.

What extremes one goes to in all this testing depends on how important ones product is.

Sorry. I did not mean to bash on TDD or otherwise.

Just trying to expressing how I feel about how Rust fits with various approaches and suggesting that perhaps a little change in approach might ease the frustration people have expressed about the Rust development cycle.

There is nothing black and white here.

1 Like

I mean modularization beyond the good practice, as in "this module ideally belongs in this crate, but I'll move it to another instead, so it will get recompiled less often".

I mean the time it takes to release a fix to production. It doesn't imply the production code is bad or untested. The world changes around code, so there always may be need to react, e.g. a 3rd party API may be down and I may need to switch it to another ASAP. Or my site may be getting spammed and I'll need to add tighter limits.

If I can build code quickly, I can rely on being able to be agile with the code itself, which to me is easiest and most flexible solution. But if I can't build the code quickly, I have to put more effort in ahead-of-time prevention, develop other ways of making changes quickly. This means that build time has a ripple effect that affects designs and development costs.

7 Likes

Compile times are a very non-linear scale for me. Below a certain amount of time ~15 seconds, barely notice them, but above that I have time to get distracted and my productivity drops. Luckily most of my rust projects are small enough for that not to be a problem

2 Likes

Compile times can be a big deal in game development, where there is no way to know how the game will play without re-compiling and restarting the game. Games are one of those things where it isn't necessarily a bug that makes you re-compile the program, but the fact that there is no way to know exactly how the physics, rendering, feel, or "funness" factors are going to be effected by the completely valid logic of the game.

This means that when writing games, writing bindings to scripting languages such as Lua or providing some method of scripting that lets you compile tiny Rust programs or something like that that you can compile/run very quickly becomes important and a large influencing part of the design of the game or engine.

Granted with a game you are probably going to want to go as far as hot reloading and such, which makes you consider those design decisions around compile times and scripting anyway, but even the simplest Pong game was taking 30 seconds to 1.5 minutes to re-compile on my laptop which made it very difficult to experiment and learn how the engine worked.

12 Likes

Wow, I just came to ask something about compilation time optimization so I can tell why it's already boring for a few thousand LOC project. :slight_smile:

I realize some people say it's not a problem "because RLS is fast". So they seems to rely on compiler as a checker.

It's OK, but if you want to check your program behavior, you have to execute it, sometimes very often per day. In video game/UI programing/embeeded, your program could compile but there can be bugs inside your game/UI/electronic. And yet, we have incremental compilation.

Even for C++ project, you sometime have to wait a lot for CI. I never tested with rust yet but having CI with a big code base in rust looks scary.

I'm very new to rust so I still have to learn good habits, but compile time seems to increase quite fast on my tiny projects. Having a compile profiling would be interesting.

Keep the good work! :heart:

1 Like

If you mean the Rust teams profiling rustc's performance on a standard benchmark suite before and after each change to its source code, that would be https://perf.rust-lang.org/. It's already standard to block merging PRs on a "perf run" to ensure there are no unintended regressions.

If you mean you yourself profiling rustc's performance on an ad-hoc basis against whatever code you're trying to build with it, I believe the latest and greatest in this space is the new-ish -Z self-profile flag.

You might also be asking about PGO: https://doc.rust-lang.org/rustc/profile-guided-optimization.html

Hopefully it was one of those :sweat_smile:

6 Likes

I like longer compilation times because it makes me feel my binary is more high quality once it's done. If I could increase compile times and leave it on overnight, I would.

10 Likes

I have a ~150K line Rust project. It takes > 10 minutes to build. This really hurts my productivity because there's a significant amount of time I'm just sitting around waiting for the build to finish so I can run tests. (I'm still glad to be using Rust, but a fast compiler would make it so much better).

4 Likes

Therefore I think a truly fast Rust compiler (which basically means, to me, something that can parallelize the end-to-end build effectively (up to 32 cores say) in the presence of long chains of crate dependencies) would be transformative for many existing Rust users and for expanding the scope where Rust is appealing.

It's such an important problem but I guess it would take a significant commitment of resources to pull it off or prove it's genuinely impossible.

One of the most promising ( to me, who doesn't know much about it ) ideas I'd heard for the compiler was to use the WASM target and cranelift to generate machine code quickly for debug builds, but I don't think its really close to being a possibility at the moment ( just from what little I've seen while browsing GitHub ).

I'm guessing that part of the limit to Rust's compile speed comes from the fact that it uses LLVM as the compiler backend, which is something that the Rust community doesn't maintain ( and isn't written in Rust ). Using cranelift provides a 100% Rust solution, even if you still wanted to use LLVM for the release builds.