Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Too bad graydon didn't get his way with build times. I've come to believe that the most important feature of any development environment is to minimize the built-test-debug cycle. Of course, a real system has many different ones, ranging from "language level" to "I have to redeploy and perform a complex series of actions in an app or 3". But at the language level I've found that build performance is of paramount importance. And when a project ignores build perf, everyone suffers every time they build. Since the lower-limit is the language compiler, it should therefore be kept very fast. (And the people working on the applications must constantly resist adding features that slow the BTD loop down any further.)

A good example of this trade-off in Java is Lombok. A very handy library that legitimately avoids a ton of boilerplate, but it also absolutely tanks your build time. In a real system, a large one, your team is better off just getting good enough with their editor that they can generate the hateful boilerplate, and leave Lombok out. Because you'll be paying for Lombok all the time, and only need it a small fraction of the time. There are hundreds, thousands of these conveniences that are deeply tempting but should be avoided, in every build. The problem is that the programmers become attached to these little nicities and actively resist giving them up, even though they are so costly.



On top of this, there's this bogus mantra in the Rust community that "if it type checks then it works."

I've spent of hours interactively debugging Rust code, crawling through tracing output etc, and hours waiting for Rust code to link with mold because I added an eprintln somewhere, so I'm not convinced.

I love writing Rust and think it makes my life easier, but there's this stockholm syndrome about compile times. It sucks, and it's not the type system or borrowchecker's fault.


> there's this stockholm syndrome about compile times. It sucks, and it's not the type system or borrowchecker's fault.

What do you mean?


The bottlenecks in Rust builds arent't type checking/borrow checking. It's things like macro expansion, module resolution and compilation, codegen from LLVM IR, and linking. Some of these things have workarounds like sccache, using mold instead of the system linker, etc but others are problems that not only remain unsolved but are actively getting worse in the ecosystem.


>hours waiting for Rust code to link with mold because I added an eprintln somewhere

How is that Rust's fault?


I think the "with mold" comment is expressing that even with the state-of-the-art fastest linker that's generally available for use with Rust, it still is slow. If you used the default linker, it would be even slower.


> I've come to believe that the most important feature of any development environment is to minimize the built-test-debug cycle.

I think the next innovation in statically typed languages should be to somehow break the build-test-debug cycle. We basically have the same interface to programming as dynamically typed languages, despite having considerably more information available because of the types. This should be exploitable somehow to give typed languages more advantages, and change the very nature of the loop.


>A good example of this trade-off in Java is Lombok. A very handy library that legitimately avoids a ton of boilerplate, but it also absolutely tanks your build time.

I don't think this is actually true right now and for a while.

>In a real system, a large one, your team is better off just getting good enough with their editor that they can generate the hateful boilerplate

Which you can get by delomboking if you really need to.


I'm not here to advocate for Lombok. However, you are first that I saw here to complain about much slower compile times. Can you teach me more? On a multi-core 5GHz desktop PC with 64GB RAM, who is really thinking about Java compile times these days? And I have worked on 1M+ line projects. Sure, the first compile is slow, but after, everything is incremental.


Nobody complains about the Java compiler. Everyone complains about the class loading performance.


My only experience with very bad class loading performance was debugging the Eclipse Collections. Single handling, it was the worst I ever saw. Everything else is manageable. Does anyone know why that particular JAR is so bad?


It's not the compiler, in this case. Lombok generates code, and for reasons (which I have since forgotten) it always generates code and invalidates incremental builds in gradle, for example, at least when used in combination with ORM annotations. This happened at a previous contract on a company computer so I don't have the links, but IIRC the gradle docs mention the interaction(s).

I wanted to delombok to save 30s off of each build, but the rest of the team(s) refused to let it go. I thought, and still think, that was a short-sighted mistake.


I don't understand the big issue with build times: I have always found that they are almost instant for incremental builds (assuming you use lld or mold).


> I have always found that they are almost instant for incremental builds (assuming you use lld or mold)

They are not almost instant once your project grows to a certain size, which is still well within the bounds of a realistic single company’s project (I work on Materialize which is all in rust).


And you have it set up with multiple compile units, shared generics, and lld (or mold ideally)?


> multiple compile units

Yes

> shared generics

I don't know what that is. Some googling suggests that it's a nightly-only feature, whereas we use the stable compiler. If it's something that can be done in stable, I'd appreciate a pointer.

> lld (or mold ideally)

    $ echo $RUSTFLAGS
    -C link-arg=-fuse-ld=lld -C debuginfo=0


In C++ a small change to a header can result in having to rebuild thousands of different files. Even if each file builds fast the total can be long. I have also benchmarked including a specific header (not using it, just including it) costs .5 seconds which adds up quick in those thousand files. Another benchmark found a specific boilerplate code construct added .1 seconds to the time to compile the file each time you added that one line - and it was a line commonly repeating in a header (MOCK_METHOD from gmock - there is a FAQ entry on how to get this time down)


I do not think it has anything to do with C++. If you are using language that is strongly typed and compiled upfront and have defined some MYTYPE that is used in thousands of files all those need to be recompiled should you change the definition of MYTYPE.


Then you're not working on big enough projects or in ecosystems where you need to regularly perform clean compiles, because afaik the "incremental" output from cargo/rustc isn't relocatable.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: