6 ms·
Drilling into the original article where Jarred explained the reasoning behind the change, It's pretty clear that under zig the team was doing things by hand th
by mrothroc 3mo ago
Drilling into the original article where Jarred explained the reasoning behind the change, It's pretty clear that under zig the team was doing things by hand that are automatic in rust.
Humans and agents share one thing: they are both non-deterministic. He talks about the issue of tracking memory lifecycles manually in zig so it can be explicitly freed. As expected, this leads to a long list of bugs where people missed things.
Rust does this automatically. It removes an entire class of errors from his backlog. From an engineering management perspective, this looks like a pretty good trade.
The bonus here is that compiler errors are exactly the kind of deterministic guardrail you need to put around coding agents. Claude works really well if you give it a way to test for correctness and "make it compile" is a pretty good target.
There's a general version of this: the artifact you expose plus the test you run on it. Deterministic tests turn stochastic output into a hard guarantee. Wrote it up here if useful: https://michael.roth.rocks/blog/verification-surface/ https://michael.roth.rocks/blog/verification-surface/
- awesan 3mo agoZig (like C) is simply not a good language to use if you're going to do many small allocations with uncorrelated lifetimes. To write robust Zig (or C) code, you must manage lifetimes yourself, for example by grouping allocations on an arena or by having fixed buffers of "things". You can just do that, and then Zig is really no less robust than Rust. But if you want to do "managed language" style allocation patterns (like what llms generally prefer), it doesn't make sense to use it.
- mrothroc 3mo ago[dead]
- hugmynutus 3mo agoThis reads like cope because you're re-inventing RAII from first principles. I cannot take this seriously as tutorials on robust Zig Allocation Pools will store a deinit method for each item within the pool, so when the pool deinits, all internal objects can be deinit'd. That is just RAII & dtors from first principles, except with extra overhead of manually storing fat pointers yourself (and the bugs that come with this). Instead of using a language with builtin guarantees & optimizations around handling this so your object pools don't need to carry around a bunch of function pointers. C++ has aggressive de-virtualization passes so at runtime a lot of the 'complex object hierarchies' can be flattened to purely static function calls.
- jstimpfle 3mo agoI've argued elsewhere some things that are wrong with RAII and C++ objects in general. Here I would just like to mention that if you have to rely on "de-virtualization" passes, you're in a miserable situation architecturally. If you have code where the overhead of virtual function calls might be too much to pay, don't do virtual functions then. End of story. To deconstruct a pool of objects, I don't see what should ever be wrong with a function pointer. The overhead of loading the function pointer will get divided by the number of objects being deconstructed. Care to explain what's the issue here?
- hugmynutus 3mo ago> I don't see what should ever be wrong with a function pointer. [...]Care to explain what's the issue here? 1. You're writing code you don't have to 2. That adds runtime overhead 3. That when you screw up has non-trivial security & resource management side effects This is objectively indefeasible in nearly any vaguely professional context.
- jstimpfle 3mo ago1. No, you're not writing code you don't have to. It's not different to implementing this as non-virtual methods, in fact I'd argue doing simple functions is more straightforward. 2. And the code being compiled is abstract & generic, it won't be instantiated for every type and bloat the executable or instruction cache. 3. Security concerns: With C++ virtual methods every object carries a mutable pointer too (to a vtable containing function pointers). What resource management side effects please?
- kllrnohj 3mo agoRe #3: vtable pointers aren't mutable...?
- jstimpfle 3mo agoOf course they are. The pointers to the vtable are part of the object. They aren't mutable fields as per the language, but for security concerns it doesn't matter what the language thinks. Being part of the object, the vtable pointer has to live in a writeable memory mapping (like stack / heap).
- kllrnohj 3mo ago> You can just do that, and then Zig is really no less robust than Rust. If you just don't write bugs, then yes all languages are equally robust, including assembly. Zig, like C, is simply not a robust language. I don't know why this feels like something contentious? It's clearly not intended to be robust?
- jackclayton 3mo agoAbove poster is talking about thinking in terms of grouped lifetimes and bulk allocations/deallocations, which is better for performance, and makes Rust borrow checking and other RAII style features pointless as they don't add any safety benefits. This video completely changed the way I think, and I subsequently moved on from Rust: https://www.youtube.com/watch?v=xt1KNDmOYqA https://www.youtube.com/watch?v=xt1KNDmOYqA
- audunw 3mo agoZig is intended to be as robust as it can be as long as it doesn’t implicitly add code (no destructors that run code you didn’t explicitly call), or increase compiler complexity and compilation time. I don’t think it makes sense to say Zig is or isn’t intended to be robust in general. Like, we don’t say Rust isn’t robust since it doesn’t add dependent types and general purpose static verification that can do more general proofs. It’s focused on eliminating one class of memory bugs in particular, exactly the class of bugs that are the biggest challenge for software like Bun, and other software with complex lifetimes (it originated from Mozilla and Rust is perfect for browsers) Zig is intended to be robust for software like TigerBeetle, or the Zig compiler itself, where memory lifetimes are simple. I’d say the focus on built in tests, fuzzing, debug memory allocators and safe mode shows that Zig is absolutely intended to be robust, within the scope of what the language aims to be. Far more than C itself or most of its popular compilers ever did.
- eru 3mo ago> Like, we don’t say Rust isn’t robust since it doesn’t add dependent types and general purpose static verification that can do more general proofs. Give it a few years! I've noticed an explosion in interest in formal verification recently, especially since nowadays the bar to entry is so low: just ask your LLM agent to give it a go.
- cyber_kinetist 3mo agoI think the main issue is that Bun relies heavily on existing C++ libraries like JavascriptCore, and these require RAII and ref-counting semantics from C++ that are closer to Rust than Zig. You could write a JS engine with Zig-like idioms (arena allocation, static initialization), but that would require re-writing the whole JS engine from the ground-up (though I would definitely be interested in it if someone actually tries to do it!)
- ttflee 3mo agoWhy not using Swift?
- norman784 3mo agoSwift is very weak outside Apple ecosystem, compared to Rust. Not sure nowadays, but Swift used to have breaking changes each major release, that's a non go for a big project.
- Ygg2 3mo agoAndreas Kling talked about it. It boils down to C++ interop sucks (no surprise for lang made by Apple), ecosystem is tiny, Rust works well enough with LLMs. https://youtu.be/DbHjKi_jASY https://youtu.be/DbHjKi_jASY
- hresvelgr 3mo ago> You can just do that, and then Zig is really no less robust than Rust. That's just it, using Zig required more rigorous engineering than the Bun team were capable of.
- rob74 3mo agoPeople tried to "just do that" (write their programs in a memory safe way) in C and other languages with manual memory management for decades, and we have countless vulnerabilities that prove this simply doesn't work. That's why newer languages, with the notable exception of Zig, prefer more advanced memory management methods.
- hresvelgr 3mo ago> People tried to "just do that" (write their programs in a memory safe way) in C and other languages with manual memory management for decades, and we have countless vulnerabilities that prove this simply doesn't work. Who are these "people" you speak of? It's possible to write software in low level languages that don't have these problems. Not a "non-zero" it might be possible, it can be done thoughtfully, and the popular notion it can't be done is backed only by incomplete anecdotes. Should everything be written in low-level languages? No, that would be absurd. Is it a simple fact of life that not every person/team/organisation is capable of meeting certain standards of rigour? Yes. That's not to say anyone in the Bun team could not become sufficiently competent in the future. For whatever reason, current experience, incentives, and personal motivations did not make for a conducive environment to make Bun watertight in Zig.
- rob74 3mo agoYes, it's possible. It's also possible for experienced pilots to fly an airliner completely manually for the full duration of a transatlantic flight without crashing. Still, over the last decades, autopilots and other assistance systems with ever more sophisticated features have been developed, and I would argue that without this technology crashes would be much more frequent than they are today. Same goes for memory management: you can do it manually, and it might work out most of the time, but if the programming language is helping you with it, the likelihood of memory safety issues decreases drastically. And the problem with avoiding these issues only by "meeting certain standards of rigour" is that you might only find out that you have failed to meet them years later, when you learn that your software has a vulnerability.
- Jarred 3mo agoGrouped and arena allocations work really well in Zig. For awhile, we tried to use this pattern almost everywhere in Bun but it gets really tricky when there’s some GC-managed memory and you want to free things incrementally to reduce RSS. Also, using arenas for arrays that grow wastes memory a lot since it keeps every previous version around (mimalloc arenas are slightly better for this) Grouped allocations works especially well in parsers & ASTs where the lifetime is very bounded. Since the Rust rewrite, we still use arenas for Bun’s parsers and the bundler but not a ton elsewhere.
- HexDecOctBin 3mo ago> using arenas for arrays that grow wastes memory a lot since it keeps every previous version around Not if you use segmented arrays https://danielchasehooper.com/posts/segment_array/ https://danielchasehooper.com/posts/segment_array/
- deleted 3mo ago[deleted]
- eddd-ddde 3mo agoZig is always _less_ robust than rust. Even if you have a single allocation you can always forget to free it.
- latortuga 3mo agoI seem to recall this Rust rewrite is all "unsafe" meaning it really doesn't automatically eliminate those issues.
- mrothroc 3mo agoRelevant passage from Jarred's post: "At the time of writing, about 4% of Bun's Rust code sits inside an unsafe block (~13,000 unsafe keywords across ~27,000 lines / ~780,000 lines), and 78% of those blocks are a single line — a pointer that came from C++, or one call into a C library. I expect this number to go down over time as we refactor from a faithful Zig port (which had no greppable unsafe keyword) to idiomatic Rust, but we are going to continue using C & C++ libraries like JavaScriptCore so it will always have more unsafe than pure Rust projects."
- dwattttt 3mo agoRelative "number of unsafe keywords" or "lines inside unsafe blocks" isn't a good metric. It's unsafe to call a C library that gives you a raw pointer, that can be a single line. It's unsafe to use that pointer, that could be a second single line. Carrying that pointer around, the data structures it's in, that's all safe, and doesn't implicate lifetime checking at all, so Rust will let you do silly things with the actual lifetime. A better metric would be absolute unsafe keywords (because each carries a need to review), or "code in a module that uses unsafe anywhere" vs total code, because module boundaries isolate unsafe.
- NohatCoder 3mo agoYeah, one needs to understand that "unsafe" does not mark which parts of the code are actually unsafe, it simply marks parts where the compiler ignores parts of its rule set. But the implications can crop up anywhere, there is no guarantee that a resulting use-after-free or similar can only happen inside the unsafe blocks. In short, if you use an unsafe block, then potentially any part of your code is unsafe.
- 3mo ago
- BearOso 3mo ago> Rust does this automatically. A garbage collected language does this automatically. Rust still requires thinking about and tracking memory lifecycles, but the borrow checker will complain and keep you from doing it wrong. That's why LLMs like Rust. It gives immediate feedback on what to fix. By-default constant reference parameters helps prevent major performance problems.
- Diggsey 3mo agoYou're getting confused between lifetimes (the static analysis that prevents use after free and similar errors) and lifecycles (more commonly discussed under the heading of ownership) which determines when objects (and thus memory) are allocated and deallocated. Ownership is automatic. You don't have to explicitly drop things when they go out of scope. (although the responsibility for that is split between the compiler and the library code). Lifetimes are not automatic, but also have no effect on memory allocation. They are purely a static analysis path and you can make a functioning rust compiler that completely ignores lifetimes.
- soulbadguy 3mo ago> You're getting confused between lifetimes (the static analysis that prevents use after free and similar errors) and lifecycles (more commonly discussed under the heading of ownership) which determines when objects (and thus memory) are allocated and deallocated. Ownership is That's a semantic distinction which does not matter in the point OP is making. And contrasting rust static approach to general GC.
- gcr 3mo agoIt’s my understanding that bun was ported to unsafe rust, so even these gains would require additional effort on the team’s part, right?
- Ygg2 3mo agoUnsafe Rust doesn't automagically disable typesystem (& borrow checker, but lifetime are a sort of types). Once raw pointer is turned into a T, &T or &mut T, the borrow checker is on.
- gchamonlive 3mo ago> Rust does this automatically. It removes an entire class of errors from his backlog. Even with the huge amount of "unsafe" rust currently in bun? https://news.ycombinator.com/item?id=48967630 https://news.ycombinator.com/item?id=48967630
- theshrike79 3mo agoYou think it’ll all stay there? Of course they’ll iterate and remove the unsafe bits which were necessary for the transition
- windexh8er 3mo agoExcept the transition was never necessary. Yet another Anthropic marketing effort so they could claim a shallow victory [0]. [0] https://andrewkelley.me/post/my-thoughts-bun-rust-rewrite.html https://andrewkelley.me/post/my-thoughts-bun-rust-rewrite.ht...
- theshrike79 3mo agoCreator of language has opinions on big project moving off language. News at 11.
- windexh8er 3mo agoAhh, yes another garbage comment that adds no value. Thanks for your contributions!
- gchamonlive 3mo agoWriting a useless comment just to tell you: oh the irony, writing a garbage comment for calling out a garbage comment. I'm lost in the layers of slurry.
- windexh8er 3mo ago
- portly 3mo agoLLMs catch memory bugs quite easily in my experience. All of this is just a (succesful) marketing stunt by Anthropic.
- m00dy 3mo agoRust is the clear winner of LLM era, you can't say otherwise.
- bluegatty 3mo agoGood thing there are tons of languages that do that out of the box, and which are frankly quite fast.
- zombot 3mo ago> "make it compile" is a pretty good target. But only as far as "make it compile" is a good predictor of runtime behavior. In C++ for instance, I can "make it compile" and it still crashes at runtime or does other undesirable things.
- raverbashing 3mo ago> He talks about the issue of tracking memory lifecycles manually in zig so it can be explicitly freed. As expected, this leads to a long list of bugs where people missed things. Yes, and again the "you're holding it wrong" people or "you are not a good enough developer" people will try to do juggling with a chainsaw and lose a couple of fingers in the process Claude Code's endorsement (and real-world testing) speaks louder than internet discussions that are at this point 30 years old (and probably more)
- deleted 3mo ago[deleted]
- boutell 3mo agoI thought that this was just an initial translation to unsafe rust in which they haven't actually gained any of those benefits yet, although presumably they can go there quickly now.
- throwaway613746 3mo ago[dead]
- kimjune01 3mo agoi found the same thing with Rust, verification steps are really helpful for speed and correctnesss
- Nimitz14 3mo agoAi slop