News for hackers. Stuff that matters.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by ameliaquining on Sunday July 13, 2025 @11:06AM (#44550945)
"No more [...] slow compile times with complex ownership tracking."

Presumably this is referring to Rust, which has a borrow checker and slow compile times. The author is, I assume, under the common misconception that these facts are closely related. They're not; I think the borrow checker runs in linear time though I can't find confirmation of this, and in any event profiling reveals that it only accounts for a small fraction of compile times. Rust compile times are slow because the language has a bunch of other non-borrow-checking-related features that trade off compilation speed for other desiderata (monomorphization, LLVM optimization, procedural macros, crates as a translation unit). Also because the rustc codebase is huge and fairly arcane and not that many people understand it well, and while there's a lot of room for improvement in principle it's mostly not low-hanging fruit, requiring major architectural changes, so it'd require a large investment of resources which no one has put up.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by unscaled on Sunday July 13, 2025 @12:52PM (#44551720)
I know very little about how rustc is implemented, but watching what kind of things make make Rust compile times slower, I tend to agree with you. The borrow checker rarely seems to be the culprit here. It tends to spike up exactly on the things you've mentioned: procedural macros use, generics use (monomorphization) and release builds (optimization).

There are other legitimate criticisms you can raise at the Rust borrow checker such as cognitive load and higher cost of refactoring, but the compilation speed argument is just baseless.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by SkiFire13 on Sunday July 13, 2025 @01:41PM (#44552049)
Procedural macros are not really _that_ slow themselves, the issue is more that they tend to generate enormous amount of code that will then have to be compiled, and _that_'s slow.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by ameliaquining on Sunday July 13, 2025 @02:12PM (#44552276)
Also the procedural macro library itself and all of its dependencies have to be compiled. Though this only really affects initial builds, as the library can be cached on subsequent ones.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by Arnavion on Monday July 14, 2025 @04:24AM (#44557648)
Proc macros themselves are slow too. If you compile them in debug mode, they run slowly. If you compile them in release mode, they run faster but take longer to compile. This is especially noticeable with behemoth macros like serde that use the complicated syn parser.

Compiling them in release mode does have an advantage if the proc macro is used a lot in your dep tree, since the faster invocations compensate for the increased compile time. Another option is shipping pre-compiled macros like the serde maintainer tried to do at one point, but there was sufficient (justified) backlash to shipping blobs in that case that it will probably never take off.

Here's a comparison of using serde proc macros for (De)Serialize impls vs pre-generated impls: https://github.com/Arnavion/k8s-openapi/issues/4#issuecommen... In other words the amount of code that is compiled in the end is the same; the time difference is entirely because of proc macro invocation. 5m -> 3m for debug builds, 3.5m -> 3m for release builds. It's from 2018, but the situation is largely unchanged as of today.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by dathinab on Monday July 14, 2025 @08:13AM (#44559241)
yesn't they require you to compile a binary (or multiple ones when nested) before being able to compile your binary and depending on a lot of factors that can add quite a bunch of overhead especially for non-incremental non-release builds (and probably can be fixed by adding sand-boxing for reproducibility making most of them pure cache-able functions allowing distributed caching of both their binaries and output, like theoretically, not sure if rust will ever end up there).

And the majority of procedural macros don't produce that much code and like you said their execution isn't the biggest problem.

E.g. the recent article about a db system ending up with 30?min compiler times and then cutting them down to 4min was a case of auto generating a whole (very enormously huge) crate (no idea if proc-macros where involved, didn't really matter there anyway).

So yeah, kinda what you said, proc macros can and should be improved, but rarely are they the root cause.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by norman784 on Monday July 14, 2025 @09:18AM (#44559852)
The issue, most commonly noted by devs, with proc macros is that it slows down the incremental compilation times, because proc macros are recomputed each time.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by nextaccountic on Monday July 14, 2025 @08:47PM (#44566829)
There's no reason proc macros invocations can't themselves be cached. For the few macros that are not idempotent (an idea that is itself absurd) an attribute like `#[proc_macro_non_cacheable]` should be available
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by josh11b on Sunday July 13, 2025 @12:55PM (#44551746)
https://learning-rust.github.io/docs/lifetimes/

> Lifetime annotations are checked at compile-time. ... This is the major reason for slower compilation times in Rust.

This misconception is being perpetuated by Rust tutorials.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by estebank on Sunday July 13, 2025 @01:15PM (#44551888)
On the phone, so I can't now, but someone should file a ticket to that project about that error: https://github.com/learning-rust/learning-rust.github.io/iss...

Be aware that it is not part of the rust-lang organization, it's a third party.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by JoshTriplett on Sunday July 13, 2025 @05:37PM (#44553971)
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by pjmlp on Monday July 14, 2025 @02:37AM (#44557100)
Rust is really getting hurt by at least not having some kind of interpreter like OCaml and Haskell have, to dispel the perpetual of urban myths from devs without background in compilers.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by dathinab on Monday July 14, 2025 @09:01AM (#44559700)
fun fact there is work in progress to have a cranelift based backend, which isn't exactly an interpreter but more like a AOT compiler build for WASM

but it anyway does compile things much faster at the cost of less optimizations (doesn't mean no optimizations or that it's slow per-see it's still designed to run WASM performant in a situation where a fast/low latency AOT is needed, but WASM programs are normally already pre-optimized and you many have to to do certain low level instruction optimizations which it still does)

AFIK the goal is to run it by default for the dev->unit test loop, as very often you don't care about high perf. code execution but about low latency getting feedback.

Through idk. the state of it.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by pjmlp on Monday July 14, 2025 @02:17PM (#44563446)
All the best for those efforts.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by _bent on Monday July 14, 2025 @10:11AM (#44560517)
well there's MIRI
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by pjmlp on Monday July 14, 2025 @02:18PM (#44563451)
However you cannot use it as a general purpose implementation.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by nextaccountic on Monday July 14, 2025 @08:48PM (#44566833)
miri is godawful slow though
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by brodo on Monday July 14, 2025 @03:56AM (#44557485)
Also, Rust compile times aren't that bad the last time I checked. Maybe they got better and people just don't realize it?
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by zimpenfish on Monday July 14, 2025 @07:08AM (#44558718)
> Also, Rust compile times aren't that bad the last time I checked.

I dunno - I've got a trivial webui that queries an SQLite3 database and outputs a nice table and from `cargo clean`, `cargo build --release` takes 317s on my 8G Celeron and 70s on my 20G Ryzen 7. Will port it to Go to test but I'd expect it to take <15s from clean even on the Celeron.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by fn-mote on Monday July 14, 2025 @07:42AM (#44558975)
I don’t think build time from `clean` is the right metric. A developer is usually using incremental compilation, so that’s where I want the whatever speed I can get.

Nobody likes a 5m build time, but that’s a very old slow chip!

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by lerno on Monday July 14, 2025 @03:16PM (#44564170)
"Incremental compilation is fast", is something people only talk about when normal compilation speeds are abysmal. Sadly, C++ set the expectations here, which made both Rust and Swift think that compilation times in the minutes is fine.

If your code compiles in 1 second from scratch then what do you need incremental compilation for?

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by tialaramex on Monday July 14, 2025 @08:34PM (#44566746)
> If your code compiles in 1 second from scratch then what do you need incremental compilation for?

That's entirely fair. But, when I watch somebody like Jon Blow, with his 1 second from scratch compilation the result seems to be that he just iterates a lot more without being significantly more productive than I am. I can imagine for some parts of video game design fast iteration might be crucial, yet I struggle to imagine that compilation speed is what matters there. Systems design, art direction, plotting, these don't seem like factors where you need those one second compile times.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by nextaccountic on Monday July 14, 2025 @08:49PM (#44566844)
> If your code compiles in 1 second from scratch then what do you need incremental compilation for?

I really want incremental compilation in 100ms or less, this makes live reloading (such as with dioxus subsecond [0]) so much more enjoyable.

I don't care about the time spent on fully recompiling the whole project from scratch though.

[0] https://www.reddit.com/r/rust/comments/1j8z3yb/media_dioxus_...

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by GoblinSlayer on Monday July 14, 2025 @05:39AM (#44558087)
Also bloat. Why ripgrep is 2mb gzip compressed?
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by torginus on Monday July 14, 2025 @06:15AM (#44558303)
Because generic monomorphization generates a massive amount of machine code.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by dathinab on Monday July 14, 2025 @09:22AM (#44559904)
that can be the reason, but it's a very bad example

it's quite unlikely that it would be _that_ much smaller if it had been written in C or C++ with the _exact_ same goals, features etc. in mind.

like grep and ripgrep seem on the surface quite similar (grep something, have multiple different regex engine etc.) but if you go into the details they are quite different (not just because rg has file walking and resolution of gitignore logic build in, but also wrt. goals features of their regex engines, performance goals, terminal syntax highlighting etc.)

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by burntsushi on Monday July 14, 2025 @09:35AM (#44560083)
Responding narrowly:

ripgrep doesn't do "terminal syntax highlighting." It has some basic support for colors, similar to GNU grep.

GNU grep and ripgrep share a lot of similarities, even beyond superficial ones. There are also some major differences. But I've always said that the venn diagram of GNU grep and ripgrep has a much bigger surface area in their intersection than the area of their symmetric difference.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by torginus on Monday July 14, 2025 @10:05AM (#44560433)
I don't know the reason, but as having worked in embedded, I worked on a project that had drivers, app logic, filesystem support, TCP stack, and then some more, that fit in less that 64kb of ROM (written in C), without much trouble, 2MB for such a tool seems excessive, would love to see a breakdown of what's in there and how much space it takes up.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by GoblinSlayer on Monday July 14, 2025 @12:04PM (#44561755)
I wrote an encrypted file exchange tool, 26kb. External dependencies are files, sockets, memcpy and malloc. It's client and server in one file, so it's two times bigger than it can be. It also has complex and almost useless features like traffic obfuscation, probing resistance and hertzbleed resistance.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by GuB-42 on Monday July 14, 2025 @01:03PM (#44562507)
ugrep, which is C++ and similar in scope to ripgrep is 0.9 MB on my machine, ripgrep is 4.4 MB and GNU grep us 0.2 MB. They all depend on libc and libpcre2.

Ugrep however depends on libstdc++ and a bunch of libraries for compressed file support (libz,...).

So yeah a bit bloated but we are not at Electron level yet.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by burntsushi on Monday July 14, 2025 @01:47PM (#44563078)
It's not clear to me that you're accounting for the difference in size that results from static vs dynamic linking. For example, if I build `ugrep` with `./build.sh --enable-static --without-brotli --without-lzma --without-zstd --without-lz4 --without-bzlib`, then I get a `ugrep` binary that is 4.5MB. (I added all of those `--without-*` flags because I couldn't get the build to work otherwise.) If I add `--without-pcre2`, I get a 3.9MB binary.

ripgrep is only a little bigger here when you do an apples to apples comparison. To get a static build without PCRE2, run `cargo build --profile release-lto --target x86_64-unknown-linux-musl`. That gets me a 4.6MB `rg` binary. Running `PCRE2_SYS_STATIC=1 cargo build --profile release-lto --target x86_64-unknown-linux-musl --features pcre2` gets a fully static binary with PCRE2 at a 5.4MB `rg` binary.

Popping up a level, a fair criticism is that it is difficult to get ripgrep to dynamically link most of its dependencies. You can make it dynamically link libc and PCRE2 (that's just `cargo build --profile release-lto --features pcre2`) and get a 4.1MB binary, but getting it to dynamically link all of its Rust crate dependencies is an unsupported build configuration for ripgrep. But I don't know how much tools like ugrep or GNU grep rely on that level of granular dynamic linking anyway. GNU grep doesn't seem to do so on my system (only dynamically linking with libc and PCRE2).

Additionally, the difference in binary size may be at least partially attributable to a difference in Unicode support:

    $ echo ♥ | rg '\p{Emoji}'
    ♥
    $ echo ♥ | ugrep-7.5.0 '\p{Emoji}'
    ugrep: error: error at position 6
    (?m)\p{Emoji}
          \___invalid character class
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by GuB-42 on Monday July 14, 2025 @06:50PM (#44566224)
These are grep, ripgrep and ugrep installed on my Debian (bookworm). The mentioned sizes are the executables only, because I think that not taking advantage of dynamic libraries if you can is a downside, though there are arguments going the other way.

Anyways, I still took it into account when calling ripgrep "bloated". Using ldd, I counted 3.6 MB of dependencies for ripgrep and 7.1 MB for ugrep. Which coincidentally result in about 8 MB for both ugrep and ripgrep. But ugrep accounts for the entire libstdc++ and other libraries, which includes code that ugrep doesn't need (such as compression), so I would have expected ugrep to be smaller. GNU grep has 2.5 MB of dependencies btw: 1.9MB for libc and 0.6MB for libpcre2.

And to make things clear, I don't put ugrep in the lightweight category either. C++ (modern C++ in particular) suffers from some of the same problems as Rust: lots of code generation leading to bloat and slow compile times, but (as you pointed out) it tends to play along better with dynamic libraries with a C interface.

I don't know how much a size-optimized grep with the same features as ripgrep would take. 4 MB looks like a lot, but sometimes bloat come from unexpected places. For example, some compression algorithms may include predefined dictionaries, coloring may involve terminal databases, and Unicode support my involve databases too.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by burntsushi on Monday July 14, 2025 @07:05PM (#44566336)
> The mentioned sizes are the executables only, because I think that not taking advantage of dynamic libraries if you can is a downside, though there are arguments going the other way.

I addressed and accounted for this in my comment. All three of GNU grep, ugrep and ripgrep can dynamically link libc and PCRE2.

ripgrep doesn't bundle any compression code or terminal databases. ripgrep does bundle a significant number of Unicode tables.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by GoblinSlayer on Tuesday July 15, 2025 @03:05AM (#44568682)
On my system grep is 136kb, dynamically linked to libc. Frankly, I don't use all its features and all its regex engines, can't remember when I searched for something more complex than fixed text. It supports coloring and references TERM variable. fgrep is 80kb, apparently supports all features except for coloring and pcre.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by torginus on Tuesday July 15, 2025 @04:50AM (#44569242)
This is a bit of an aside, but I wonder if it'd be possible to combine the advantages of dynamic and static linking - meaning no need to do dlsym calls, and virtual dispatch to call into libraries, you could have fixed addresses for functions while sharing dynamic libraries between processes.

How it would work, is the process would tell the OS what libraries it expects to be loaded and at what address, and it would just mmap that piece of shared readonly memory. This mapping step happens for shared libraries anyways, but the symbol resolution is dynamic.

I imagine this would also harden the application somewhat, as there are less dynamic dispatches for hackers to exploit.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by GuB-42 on Tuesday July 15, 2025 @07:43AM (#44570134)
If you knew in advance the addresses of each function, it wouldn't be very dynamic. It would be akin to statically link the entire system, which makes sense in embedded systems, but probably not on a system where you would use ripgrep.

It seems that what you are suggesting is using position dependent code, which has performance benefits, especially on 32-bit x86, but it seems that we are moving away from it, one reason being that modern hardware supports position independent code better, and also for security.

Having fixed addresses means that hackers know exactly where functions are, making their life easier for writing their shellcodes. As a result, a common security feature we tend to see more and more is ASLR, where code is relocated at random addresses, even for statically-linked code, which is the exact opposite of what you are suggesting.

What you are suggesting could protect against things like DLL injection, which is something I consider more of a feature than a bug. For me, the small improvement in security is not worth it, especially since it would be incompatible with ASLR. Some of these benefits could be achieved by hardening the dynamic linker without changing the executables and libraries themselves.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by torginus on Tuesday July 15, 2025 @10:28AM (#44571517)
It doesn't have to be dynamic 99% of the time, most/all of your dependencies tend to be static in the sense that you know them in advance. Yet you'd still have less memory footprint than static linking, better startup time than both dynamic linking (no symbol resolution) and static linking (less stuff to load).

Not sure what you're suggesting with position dependent code. All libraries would still be position independent, but libfoo would be loaded at 0x5000000 in executable A and 0x6000000 in executable B.

For ASLR, you'd have the exact same performance and security characteristics as statically linked code. Either you could go position dependent and forgo ASLR, or go position independent and randomly shift your base address, in which case the loaded libs would need to account for that (for example if ASLR decides to load your process at 0x10 then libfoo would be loaded at 0x5000010).

Also I don't see any reason why you couldn't combine this with dynamic linking, and static linking in the same process.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by burntsushi on Monday July 14, 2025 @08:43AM (#44559514)
If you're talking about the release binary, that has an entire libc (musl) statically linked into it. And all of PCRE2. And all of its Rust dependencies including the entire standard library.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by Philpax on Monday July 14, 2025 @09:33AM (#44560055)
Is that a lot for an application that does what it does?
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by torginus on Monday July 14, 2025 @06:12AM (#44558282)
Generally why I think rust compile is unfixably slow is the decision to rely on compile-time static dispatch, and heavy generic specialization, which means there's a LOT of code to compile and the resulting binary size is large.

Many-many people remarked that this is the wrong approach in todays world, where CPUs are good at doing dynamic dispatch prediction, but the cache sizes (esp. L1, and instr cache) is very limited, for most code (with the exception of very hot tight loops), fetching code into cache is going to be the bottleneck.

Not to mention, for a systems programming language, I'd expect a degree of neatness of the generated machine code (e.g. no crazy name mangling, having the same generic method appear 30 places in assembly etc.)

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by ameliaquining on Monday July 14, 2025 @08:22AM (#44559323)
People say this a lot, but it doesn't seem to be borne out in practice very often. https://matklad.github.io/2021/07/10/its-not-always-icache.h...
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by dathinab on Monday July 14, 2025 @08:49AM (#44559583)
> is unfixably slow

it's not at all unfixable, I mean sure there is a limit to speed improvements but many of the things you mention aren't really as fundamental as they seem

one one hand you don't have to go crazy with generics, `dyn` is a thing and not being generic is often just fine. Actually it's not rare to find it projects code guidelines to avoid unnecessary monopolization e.g. use `&mut dyn FnMut()` over `impl FnMut()` and similar. And sure there is some issue with people spreading some "always use generics it's faster, dynamic dispatch is evil FUD" but that's more a people then a language problem.

on the other hand rust gives very limited guarantees about how exactly a lot of stuff happens under the hood, including the rust calling convention, struct layout etc. As long as rust don't change "observed" side effects it can to whatever it wants. Dynamic/Static dispatch is in general not counted as a observed side effect so the compiler is free to not monomorphe things if it can make it work. While it already kinda somewhat doesn't monomorphize some part (e.g. T=usize,T=u64 on 64bit systems) there is a lot of untapped potential. Sure there are big limits on how far this can go. But if combined with not obsessing with generics and other improvements I think rust can have very reasonable compile times, especially in a dev->unit test loop. And many people are already fine with them now so nothing I'm overly worried about tbh.

> neatness of the generated machine code

Why would you care about that in a language where you close to never have to look at assembly of it or anything similar? It's also not really what any other languages pursue, even in modern C that is more a side effect then a intend.

Through without question kilobytes large type signatures are an issue (but the mangling isn't, IMHO if you don't use a tool to unmangle symbols on the fly that is a you problem).

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by torginus on Monday July 14, 2025 @10:16AM (#44560586)
It's unfixable in the sense that the problem isn't with how fast the compiler is, it's that you give it a ton of extra work. You could try to convince the library devs to use more dyn, but it'd require a culture shift. I don't think the compiler going behind the users back and second guessing whether to use static dispatch or inlining is something a low-level language should do. Java, sure.

In fact I define a systems language as something that allows the dev to describe intended machine behavior more conveniently, as opposed to a higher-level language, where the user describes desired behavior and the compiler figures out the rest.

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by ameliaquining on Monday July 14, 2025 @04:31PM (#44564907)
It's not all inherent language-semantics issues like monomorphization. rustc currently generates LLVM IR in a fairly naive/brute-force-ish way. The resulting machine code is as good as you'd get with more carefully generated LLVM IR, because LLVM is very good at optimizing, but it takes longer to get there. Some of the work that LLVM currently does could instead be done in earlier compilation passes, and they could do it faster by exploiting relevant context that LLVM doesn't have. But again, this'd require significant architectural changes, which is why it hasn't already happened.

Also it could maybe make sense for debug builds to let the compiler choose whether to use static or dynamic dispatch, with an attribute to force static dispatch in those cases where it's absolutely required. (I vaguely recall some kind of attempt to do that, that got stuck because it had trouble dealing with associated constants or something like that. But I can't find it now.)

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by nagisa on Monday July 14, 2025 @11:14AM (#44561176)
There are compile-time techniques that can mitigate the compile-time cost of monomorphization to a degree: optimizing on a generic IR (MIR) and polymorphization (merging functions that produce equivalent bodies) come to mind as immediate examples that have been talked about or implemented to a degree in rustc.
Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by dathinab on Monday July 14, 2025 @07:58AM (#44559087)
> They're not;

it's complicated, and simple

the simple answer is rust compiler times are not dominated by the borrow checker at all, so "it's fast" and you can say it's not overly related to their being borrow checking

the other simple answer is that a simple reasonable well implemented borrow checker is pretty much always fast

to complicated answer is that rusts borrow checker isn't simple as there are a _huge lot_ of code a simple borrow checker wouldn't allow which is safe and people want to write and the borrow checker rust needs to run to support all that edge cases has to basically run a constraint solver. (Which a) is a thing which in O notation is quite slow and b) is a thing CS has researched optimizations and heuristics for since decades so it is often quite fast in practice.) And as far as I remember rust currently does (did? wanted to?) run this in two layers, the simple checker checks most code and the more powerful on only engages for the cases where the simple checker fails. But , like mentioned, as the compilation still isn't dominated by the borrow checker this doesn't exactly mean its slow.

So the borrow checker isn't an issue and if you create a C-like language with a rust like borrow checker it will compile speedily, at least theoretically, if you then also have a tone of code gen and large compilation units you might run into similar issues as rust does ;)

Also recently most of the "especially bad cases" project in rust have run into (wrt. compiler times, AFIK) all had the same kind of pattern: A enormous huge amount of code (often auto generated, often even huge before monomorphization) being squeezed into very few (often one single) LLVM compilation unit leading to both LLVM struggling hard with optimizations and then the linker drowning, too. And here is the thing, that can happen to you in C too and then your compilation times will be terrible, too. Through people tend to very rarely run into it in C.

> not low-hanging fruit, requiring major architectural changes, so it'd require a large investment of resources which no one has put up.

it still happens from time to time (e.g. polenious) and then there are still many "hard" but very useful improvements which don't require any large scale architectural changes and also some bigger issues which wouldn't be fixed by large scale architectural improvements. So not sure if we are anywhere close to needing a large scale architectural overall in rustc, probably not.

E.g. in a somewhat recent article about way too long rust compiler times many HN comments thought that rustc had some major architectural issues wrt. parallelization, but the issue was that rust failed to properly subsection the massive auto-generated crate when handing code units to LLVM and that isn't an architectural issue. Or e.g. not replacing LLVM with cranelift (if viable) for the change->unit test loop is a good example for a change which can largely improve dev experience/decrease compiler times for the place where it matters the most (technically it does change the architecture of the stack, and needed many many small changes to allow a non LLVM backend, but it's not "a major rewrite(architectural) change" in the rustc compiler code).

Re:Forget Borrow Checkers: C3 Solved Memory Lifetimes with S... by sim7c00 on Monday July 14, 2025 @08:29AM (#44559377)
maybe the borrow checker takes most compile time if you take an avergae of how often it runs vs. how often the next compile phases are triggered over code lifespan :') (yes ok so i dont do well with lifetimes hah)