Hacker News new | ask | show | jobs
by constexpr 2311 days ago
> If you're doing arena allocation in a compiler you might as well just leak all your allocations (which you could get with bumpalo with a 'static lifetime); then you won't have to deal with lifetimes at all.

I considered this but it's a very limiting hack. Ideally esbuild could be run in watch mode to do incremental builds where only the changed files are rebuilt and most of the previous compilation is reused. Memory leaks aren't an acceptable workaround to memory allocation issues in that case. While I don't have a watch mode yet, all of esbuild was architected with incremental builds in mind and the fact that Go has a GC makes this very easy.

> 500-line functions are hard to read.

I totally recognize that this is completely subjective, but I've written a lot of compiler code and I actually find that co-locating related branches together is easier for me to work with than separating the contents of a branch far away from the branch itself, at least in the AST pattern-matching context.

> It's hard for me to go back to a language without pattern matching and enums

I also really like these features of Rust, and miss them when I'm using other languages without them. However, if you look at the way I've used Go in esbuild, interfaces and switch statements give you a way to implement enums and pattern matching that has been surprisingly ergonomic for me.

The biggest thing I miss in Go from Rust is actually the lack of immutability in the type system. To support incremental builds, each build must not mutate the data structures that live across builds. There's currently no way to have the Go compiler enforce this. I just have to be careful. In my case I think it's not enough of a problem to offset the other benefits of Go, but it's definitely not a trade-off everyone would be comfortable making.

1 comments

> interfaces and switch statements give you a way to implement enums and pattern matching that has been surprisingly ergonomic for me.

With no exhaustiveness checking (also no destructuring, etc.)

I should also note that you can change the default stack size in Rust to avoid overflows, though there should be a bug filed to get LLVM upstream stack coloring working. It's also possibly worth rerunning the benchmark again, as Rust has upgraded to newer versions of LLVM in the meantime.

This really reeks to me of trying to shoehorn Rust into the solution rather than it being an organic fit to the problem space.

I don’t see the value in this level of thinking here. Why should any developer go through this much hassle when they have a perfectly good solution that, really, I’m not seeing any discussion about this that actually highlights issues in the approach to using ago for this sort of thing

Generally, Rust "should" be faster, because it spends a lot of time on optimizations that Go doesn't do. That's what you're paying for in compile times. If Go is faster on some CPU bound workload despite doing a lot less optimization, that's interesting. (I should note that this is not the norm.)
Or, written another way: In theory, practise is like theory. In practise, it isn't :)
I'm not sure that this is a CPU bound workload. You're right that if this is CPU bound, LLVM's code generation should come out on top, even if only slightly, but that's not the case. Perhaps writing a JavaScript bundler is more of a memory bound or I/O bound task than a CPU bound task?
What optimizations is Go not doing that Rust is that makes Rust vastly superior to Go? (Or even superior at all)

I don’t think it’s that simple. I understand Go uses garbage collection but that doesn’t automatically mean Go doesn’t do compile time optimizations or is poor at CPU bound work.

While I understand GCs add overhead I don’t think that in and of itself means much here

This seems like yak shaving to me