Back to News
Advertisement
Advertisement

⚡ Community Insights

Discussion Sentiment

81% Positive

Analyzed from 2042 words in the discussion.

Trending Topics

#rust#code#memory#unsafe#zig#language#compiler#machine#runtime#more

Discussion (50 Comments)Read Original on HackerNews

steveklabnikabout 1 hour ago
I think this is a fine post. But one comment:

> remember that for compilers which emit machine code, like roc and rustc, doing memory-unsafe things is a big part of the job

I don't really think that this is true, in the way that it's written.

I think that for the hot binary patching / code reloading features, yes, that is going to need unsafe. But for regular old "producing an executable" compilation? Emitting machine code isn't the part that requires unsafe. The language's runtime is a more likely site to find unsafe.

EPWN3D38 minutes ago
Yeah that is definitely 1000% wrong. A compiler can do its job with totally abstract data structures. If anything would need to do unsafe stuff in memory, it would probably be a linker.
steveklabnik7 minutes ago
> probably be a linker

I don't think that's any different either. The core job of linking isn't particularly unsafe.

(Unless, similarly, you're doing the hot reloading stuff)

narnarpapadaddy5 minutes ago
I agree that it’s not inherent to emitting machine code but I do think it reflects a different set of priorities.

In extremely high performance code you use different data structures and algorithms and change your approach to memory allocation. TigerBeetle famously does all memory allocation once on startup.

Roc is attempting to make a similar set of trade-offs in their compiler as Zig, so it makes sense that the author finds many shared patterns.

orlp22 minutes ago
I think if you interpret it charitably it means that any bug in the emitted machine code is already a likely memory-unsafe miscompilation if it is ran.

The compiler itself might be perfectly "memory safe" but the generated binary fundamentally is always at risk (besides WebAssembly I suppose).

I'm fully aware of the separation of compiler and binary, and being able to compile untrusted code safely is nice, but a perfectly safe compiler that generates vulnerable binaries isn't that much better.

demosthanos3 minutes ago
In context that's clearly not what he's saying, the next sentence is this:

> Zig has more features than Rust for making memory-unsafe code work correctly, and that was the area where we wanted the most help.

Zig definitely does not have more features for successfully emitting memory-unsafe machine code than Rust does. I can emit memory-unsafe machine code from typescript if I really want to and nothing at all in the language will get in my way. So the sentence quoted above must refer to the idea that the compiler itself needs to be unsafe, which Steve is right is simply untrue.

steveklabnik8 minutes ago
I do think that is a good point, it's just not what the line actually says. But that's why I wasn't saying "zomg this is WRONG!!!!" but instead, trying to point out that there are subtleties here. For people who aren't as deep in the weeds in this subject, I think the details matter. But again, as I said, I like the post, this is just one thing.

I am also probably in a more pedantic mindset because, well, I'm writing a compiler in Rust, and the words as written do not resonate with me at all.

> a perfectly safe compiler that generates vulnerable binaries isn't that much better.

I do think it's much better. Eliminating classes of bugs in one component is a good thing, even if it's not every component. This is a core lesson of Rust! unsafe still exists, but going from "I don't know what is unsafe" to "only this part is unsafe" is a major improvement.

rtfeldman17 minutes ago
> I think that for the hot binary patching / code reloading features, yes, that is going to need unsafe. But for regular old "producing an executable" compilation? Emitting machine code isn't the part that requires unsafe. The language's runtime is a more likely site to find unsafe.

Agreed! Emitting machine code is not unsafe, since it's just writing bytes down - it's only once you execute that machine code that there's potentially unsafety. The reason I said "a big part of the job" is that in practice a lot of compilers both emit machine code and execute it - but you're totally right that it's not a requirement that a compiler do both.

In addition to the examples you gave (hot binary patching/code reloading, language runtime, etc.), others would be things like evaluating userspace code at compile time (e.g. const fn in Rust, or in Roc any expression that could be hoisted to the top level), running tests and inspecting their output to decide what to display to the user, etc.

Those are the types of things I had in mind when I wrote that.

steveklabnik4 minutes ago
I am disappointed you're downvoted, Richard. This is a fine reply, and I hope you know that a minor quibble with a single line in the post doesn't mean that I think it's a bad one overall.

I also think it's a good thing that you wrote the post in general, when I saw it pop up I was like "oh, of course, this post should exist!" I'm surprised I didn't think about it earlier.

> evaluating userspace code at compile time

Usually this would be done via an interpreter, so I'm not sure that it really requires unsafe either. If you are literally executing machine code, sure, but const fn in Rust and constexpr in C++ and many other languages do not do that, as it causes a number of problems (for example, cross-compilation).

Aurornis40 minutes ago
That line confused me, too. What parts of their compiler require memory-unsafe operations to produce machine code?
skybrian8 minutes ago
They are saying that running the compiled code is memory-unsafe when there is a compiler bug, and that’s what developers do next. The memory corruption happens in a different process.

In this respect, effectively all the compiler should be treated sort of like an unsafe region because it requires extra care to avoid memory corruption bugs.

Aurornis3 minutes ago
That's not what it says at all. The section we're talking about is for the compiler and emitting machine code

> we ended up with about 1,200 uses of unsafe

> remember that for compilers which emit machine code, like roc and rustc, doing memory-unsafe things is a big part of the job

paulddraperabout 1 hour ago
Agreed, that’s disturbingly incorrect.

If anything, compilers are perfect models of trees and well formed programs.

royal__4 minutes ago
I don't even know what Zig is but I've seen this topic come up so many times on this site that I'm starting to think the people who are actually doing this are unsure themselves whether it's a good idea or not.
arthurbrownabout 1 hour ago
Interesting that OCaml was flexible and expressive enough to be used as a prototype testbed but not chosen as the implementation language, especially given the maturity of both. I would be surprised if Zigs incremental builds could be meaningfully faster than dune's.

Cross compilation is great, but not mentioned in the "why Zig" section. Is memory control that crucial for a compiler?

Rust itself was originally written in OCaml, same with WASM. I'm curious about what milestone gets reached where the maintainers collectively decide to transition away.

steveklabnikabout 1 hour ago
Rust moved away from OCaml when it decided to be re-written in Rust. The post alludes to this as being a usual time for a wholesale re-write, and I'd agree.
arthurbrown3 minutes ago
I appreciate the insight, and on closer reading the post clearly states that realistically only Zig and Rust were ever considered.

Since you're here, could you comment on the approach Rust took in their rewrite? Was it more of a straight translation like Go did when they self hosted -- similar to the recent Bun transliteration? Or were there architectural changes made along the way like this article describes with Roc?

grayrestabout 1 hour ago
One of the primary goals for the Roc project is compiler speed. I presume OCaml is out of the running because it's not a systems language.
satvikpendemabout 1 hour ago
OCaml compiler is incredibly fast. I wonder how it'd fare with Jane Street's extensions for the borrow checker etc in OxCaml, if it's good enough for their HFT I'm sure it's good enough for a new language.
djha-skin10 minutes ago
I suspect this "not a systems language" alludes only to OCaml's rather steeper learning curve and until-recently difficulty with multiple threads. I am sure it could roll just fine as a single-threaded compiler language written by a small team, which indeed, it was.
antonvs25 minutes ago
I wrote a toy Scheme implementation in OCaml by using the Camplp4 preprocessor. In benchmarks, it was faster than Gambit Scheme, which compiles through C.
landr0idabout 1 hour ago
>ReleaseSafe catches use-after-free errors through runtime checks which panic if the program tries to use freed memory.

I don't know Zig so maybe they know something I don't, but I have seen no evidence that it catches any type of use-after-free including double-free?

While writing a blog post (below) I went through the documentation to figure out the possible runtime memory safety checks Zig can insert. The term "use-after-free" or "UaF" never occurs on that documentation page. Searching for "safety-checked" doesn't yield any related hits either.

Unless maybe they're using the DebugAllocator in release builds? Even that does not reliably surface UaF.

https://landaire.net/memory-safety-by-default-is-non-negotia...

veber-alex15 minutes ago
I believe you are correct.

I think ReleaseSafe just adds bound checking and panics on unreachable code.

I don't think Zig offers any temporal memory safety.

flohofwoe10 minutes ago
The DebugAllocator catches use-after-free (at least on page-level), but at the cost of never recycling memory addresses (e.g. it eats through the virtual address space).

https://ziglang.org/documentation/master/std/#src/std/heap/d...

For higher level code, "generation-counted index handles" might be the better solution to provide temporal runtime memory safety, not part of Zig the stdlib though.

Or even better: never use dynamic memory allocation and make all lifetimes 'static' :)

pjmlp9 minutes ago
Quite interesting the hand waving of security issues with Zig, oh well.

If I want to use allocator debuggers I already have the production ready tools that exist for C and C++ for at least 30 years.

onlyrealcuzzoabout 2 hours ago
Zig's incremental builds are DEFINITELY a killer feature. In the short term, I could see why you'd make a switch to get it. But, in the medium term, can we really not expect to see this in Rust in the somewhat near future?

I want to go fast, but I don't want to go fast just to shoot my foot off.

If only somehow we could get Rust's safety with all of Zig's features and Go's runtime without GC...

That's what I'm working on building [=

dabinat23 minutes ago
This is being worked on: https://rust-lang.github.io/rust-project-goals/2026/roadmap-...

Most of the goals on this page are targeted for this year.

Hinrikabout 1 hour ago
Layperson here: what is special about Go's runtime, aside from the GC?
djha-skin8 minutes ago
Chief design goals were radically easy concurrency and speed of compilation.
onlyrealcuzzoabout 1 hour ago
It's literally the most sophisticated scheduling engine in the world.

In practice, Go can typically outperform Rust in throughput (using more memory), despite having a mountain of disadvantages against it in theory.

That's how good the Go scheduler/runtime is.

jcglabout 1 hour ago
This is the first I've heard anyone claim higher throughput for Go than Rust. Any articles you'd point to to learn more?
Aurornis34 minutes ago
> n practice, Go can typically outperform Rust in throughput (using more memory), despite having a mountain of disadvantages against it in theory

This is a huge claim that disagrees with both my real-world experience and everything I've seen from artificial comparisons.

Every high performance Go system I've worked on has quickly reached the point where we're optimizing memory management and doing things that would have been explicit in a non-GC language like Rust anyway.

The Go runtime is amazingly optimized, but it comes with overhead over doing the same work directly in a lower level language.

zacmps15 minutes ago
What benchmarks are you referring to?

Rust itself doesn't have a scheduler of course, I assume this is comparing against tokio or one of the other async executors?

jandrewrogers29 minutes ago
> It's literally the most sophisticated scheduling engine in the world.

That seems unlikely regardless of how good it is. This is a domain where state-of-the-art research is not in the public literature. Scheduling is an AI-complete problem.

fnord77about 1 hour ago
Goroutines?
dnauticsabout 1 hour ago
> if only somehow we could get Rust's safety with all of Zig's features

i periodically throw my unused codex tokens at this:

https://github.com/ityonemo/clr

lioetersabout 1 hour ago
Instead of waiting for faster compiler in Rust, how about from the other direction, adding some kind of borrow checker to Zig? That sounds more within reach and practically achievable, possibly even in userland.
veber-alex19 minutes ago
It's impossible to add a borrow checker to any existing language.

The reason Rust has a working borrow checker is because every part of the language from structs, enum, traits, generics and all the way to the syntax itself has been designed to support lifetimes and borrow checking.

It's is not something you can just tack on to an existing language without fundamentally changing it.

solatic8 minutes ago
I wouldn't say it's impossible, rather un-ergonomic. TypeScript can add type information to ordinary JavaScript code via JSDoc comments; the result can both be executed as ordinary JavaScript as-is and type-checked with TypeScript. But it's a huge pain to try to write (and maintain) everything that way, it was supported as a hack to help migrate legacy codebases. You could probably take a similar "the lifetimes are embedded in comments" approach with other languages, and the result would be similarly un-ergonomic.
onlyrealcuzzoabout 1 hour ago
That's sort of what I'm doing...

I'm writing a language with Affine Ownership that transpiles to Zig and has a built-in FSM-based Green Fiber runtime.

Affine Ownership gives you memory safety + fearless concurrency + eliminates the need for Go's GC.

It's obviously going to slow down compilation - since you need to do Rust's borrow checking, etc. But I can do this incrementally as well...

dnauticsabout 1 hour ago
> how about from the other direction, adding some kind of borrow checker to Zig? That sounds more within reach and practically achievable, possibly even in userland.

It's doable, and as static analysis. see sibling comment.

Ar-Curunirabout 1 hour ago
No, it would fundamentally change how Zig works.
giancarlostoro33 minutes ago
One thing I wish Rust would improve over time is the builds. Its one of the biggest sources of wasted storage space on all my computers, builds a ton of libraries can take tens of gigs, it adds up very quickly. Not sure what the best solution is, one I found is to set the global build folder so dependencies get reused across projects, but imho it should be an OOTB default behavior whatever the real solution should be.
c-hendricks19 minutes ago
I always got a kick out of that, coming from a JavaScript background where people constantly harp on the size of node modules.

My Tauri project, where the backend is much smaller code-wise than the frontend, has 9gb of rust artifacts (node_modules is 550mb for comparison)

dev_l1x_beabout 1 hour ago
Zig is a pre-1.0 language while Rust is post-1.0. This alone is settles which one to pick for may developers. The library support is probably favours Rust too. Rust build times are much slower than Zig, I get that, but I rarely optimize software for build times.
drdexebtjl13 minutes ago
Zig is not pre-1.0 because it’s not ready for production (bugs or missing features), it’s pre-1.0 because they want to be able to make breaking language changes.

Nowadays when you can just point an agent at release notes and have it update everything, I actually prefer not having to wait through rare major releases to get new language features.

KoleSeise1277about 2 hours ago
The 35ms incremental rebuild is the part that sold me. I'd be curious to see the same benchmark on ARM once -fincremental gets there.
coffeeindexabout 2 hours ago
Didn’t know Roc was still being worked on. I think it’s an interesting concept for a language that I personally haven’t seen elsewhere
satyambnsal38 minutes ago
is this uno reverse for bun post of zig to rust port ?
Advertisement
up2isomorphismabout 1 hour ago
I think there will be soon a wave of rewriting rust to language X coming up.