Zig feels more practical than Rust for real-world CLI tools

(dayvster.com)

201 points | by dayvster 2 days ago ago

404 comments

  • simonask 2 days ago ago

    The benefit of Zig seems to be that it allows you to keep thinking like a C programmer. That may be great, but to a certain extent it’s also just a question of habit.

    Seasoned Rust coders don’t spend time fighting the borrow checker - their code is already written in a way that just works. Once you’ve been using Rust for a while, you don’t have to “restructure” your code to please the borrow checker, because you’ve already thought about “oh, these two variables need to be mutated concurrently, so I’ll store them separately”.

    The “object soup” is a particular approach that won’t work well in Rust, but it’s not a fundamentally easier approach than the alternatives, outside of familiarity.

    • mattwilsonn888 2 days ago ago

      As long as the audience accepts the framing that ergonomics doesn't matter because it can't be quantified, the hand-waving exemplified above will confound.

      "This chair is guaranteed not to collapse out from under you. It might be a little less comfortable and a little heavier, but most athletic people get used to that and don't even notice!"

      Let's quote the article:

      > I’d say as it currently stands Rust has poor developer ergonomics but produces memory safe software, whereas Zig has good developer ergonomics and allows me to produce memory safe software with a bit of discipline.

      The Rust community should be upfront about this tradeoff - it's a universal tradeoff, that is: Safety is less ergonomic. It's true when you ride a skateboard with a helmet on, it's true when you program, it's true for sex.

      Instead you see a lot of arguments with anecdotal or indeterminate language. "Most people [that I talk to] don't seem to have much trouble unless they're less experienced."

      It's an amazing piece of rhetoric. In one sentence the ergonomic argument has been dismissed by denying subjectivity exists or matters and then implying that those who disagree are stupid.

      • jasonpeacock 2 days ago ago

        > produce memory safe software with a bit of discipline

        "a bit of discipline" is doing a lot of work here.

        "Just don't write (memory) bugs!" hasn't produced (memory) safe C, and they've been trying for 50yrs. The best practices have been to bolt on analyzers and strict "best practice" standards to enforce what should be part of the language.

        You're either writing in Rust, or you're writing in something else + using extra tools to try and achieve the same result as Rust.

        • fpoling a day ago ago

          As Rust Zig has type-safe enums/sum types. That alone eliminates a lot of problems with C. Plus sane error handling with good defaults that are better than Rust also contributes to code with less bugs.

          Surely there is no borrow checker, but a lot of memory-safety issues with C and C++ comes from lack of good containers with sane interfaces (std::* in C++ is just bad from memory safety point of view).

          If C++ gained the proper sum types, error handling and templates in Zig style 15 years ago and not the insanity that is in modern C++ Rust may not exist or be much more niche at this point.

          • TuxSH 19 hours ago ago

            > If C++ gained the proper sum types

            AFAIK "P2688 R5 Pattern Matching: match Expression" exists and is due C++29 (what actually matters is when it's accepted and implemented by compilers anyway)

            Also, cheap bound checks (in Rust) are contingent to Rust's aliasing model.

          • whatevaa 12 hours ago ago

            Buffer overruns are most common memory related RCE's. So bounds checking arrays/strings BY DEFAULT is needed.

        • tptacek a day ago ago

          I actively dislike Zig's memory safety story, but this isn't a real argument until you can start showing real vulnerabilities --- not models --- that exploit the gap in rigor between the two languages. Both Zig and Rust are a step function in safety past C; it is not a given that Rust is that from Zig, or that that next step matters in practice the way the one from C does.

          • dadrian a day ago ago

            I like Zig, although the Bun Github tracker is full of segfaults in Zig that are presumably quite exploitable. Unclear what to draw from this, though.

            [1]: https://github.com/oven-sh/bun/issues?q=is%3Aissue%20state%3...

            • vanderZwan a day ago ago

              Wasn't Bun the project where the creator once tweeted something along the lines of "if you're not willing to work 50+ hours a week don't bother applying to my team"? Because if so then I'm not surprised and also don't think Zig is really to blame for that.

              • dadrian a day ago ago

                Not clear to me there's a correlation between hours worked and number of memory safety vulnerabilities

                • blacksmith_tb a day ago ago

                  I think the implication is something like "overwork / fraying morale from long hours means shipping more bugs".

                  • tptacek a day ago ago

                    The point of memory-safe languages is to foreclose on a set of particularly nasty bugs, regardless of how frayed engineer morale is.

                    • vanderZwan 18 hours ago ago

                      I'm pretty sure that in an overworked environment the engineers would reach for Rust's unsafe mode pretty quickly because they're too tired to make sense of the borrow checker.

                      • timschmidt 8 hours ago ago

                        I'm no expert, but I've been hacking in Rust for several years now, and the only unsafe I've written was required as part of building a safe interface over some hardware peripherals. Exactly as intended.

                        The borrow checker is something new Rust devs struggle with for a couple months, as they learn, then the rules are internalized and the code gets written just like any other language. I think new devs only struggle with the borrow checker because everyone has internalized the C memory model for the last 50 years. In another 50, everyone will be unlearning Rust for whatever replaces it.

                      • dadrian 13 hours ago ago

                        Web browsers and operating systems are full of memory safety bugs, and are not written by engineers in crunch these days.

          • pjmlp 20 hours ago ago

            Modula-2 was already a step function in safety past C, but people did not care because it wasn't given away alongside UNIX.

          • fuzztester a day ago ago

            >I actively dislike Zig's memory safety story

            Why? Interested to know.

            Just for background, I have not tried out either Zig or Rust yet, although I have been interestedly reading about both of them for a while now, on HN and other places, and also in videos, and have read some of the overview and docs of both. But I have a long background in C dev earlier. And I have been checking out C-like languages for a while such as Odin, Hare, C3, etc.

        • rixed a day ago ago

          > "Just don't write (memory) bugs!" hasn't produced (memory) safe C

          Yes it did, of course. Maybe it takes years of practice, the assistance of tools (there are many, most very good), but it's always been possible to write memory safe large C programs.

          Sure, it's easier to write a robust program in almost every other language. But to state that nobody ever produced a memory safe C program is just wrong. Maybe it was just rethoric for you, but I'm afraid some may read that and think it's a well established fact.

          • zanellato19 a day ago ago

            >Yes it did, of course. Maybe it takes years of practice, the assistance of tools (there are many, most very good), but it's always been possible to write memory safe large C programs.

            Can you provide examples for it? Because it honestly doesn't seem like it has ever been done.

            • rixed 16 hours ago ago

              I don't understand where you stand. Surely, you don't mean that all C programs have memory bugs. But on my side, I'm not claiming that discipline makes C a memory safe language either. This discussion has taken a weird turn.

              • ramblerman 14 hours ago ago

                > you don't mean that all C programs have memory bugs

                Well all of them "potentially" do, which is enough from a security standpoint

                There have been enough zero days using memory leaks that we know the percentage is also non trivial.

                So yes, if programmers can write bugs they will, google SREs were the first to famously measure bugs per release as a metric instead of the old fashioned (and naive) "we aren't gonna write any more bugs"

            • 6P58r3MXJSLi 20 hours ago ago

              postfix

              sqlite

              billions of installations and relatively few incidents

              • zelphirkalt 18 hours ago ago

                Few incidents != memory safe

                Few incidents != not badly exploitable

                Few incidents != no more undiscovered safety bugs/issues

                I don't think your examples quite cut it.

            • dayvster a day ago ago

              [flagged]

              • hannofcart a day ago ago

                Haven't written C in a while but I think this program has an integer overflow error when you input 2 really large integers such that the sum is more than a 32 bit signed integer.

                Also I believe in entering null values will lead to undefined behaviour.

                • Karrot_Kream a day ago ago

                  Memory safe doesn't mean protection from integer overflow unless you use that integer to index into some array.

                  I'm not sure how you'd enter NULL given scanf.

                  • Voultapher 21 hours ago ago

                    I'm not sure how showing that gp can't even write a dozen lines of memory safe C proves that doing so for the exponentially harder 100+k LoC projects is feasible.

                    The program contains potential use of uninitialized memory UB, because scanf error return is not checked and num1 and num2 are not default initialized. And a + b can invoke signed integer overflow UB. A program with more than zero UB cannot be considered memory safe.

                    For example if the program runs in a context where stdin can't be read scanf will return error codes and leave the memory uninitialized.

                    • Karrot_Kream 9 hours ago ago

                      > num1 and num2 are not default initialized

                      num1 and num2 are declared on the stack and not the heap. The lifetimes of the variables are scoped to the function and so they are initialized. Their actual values are implementation-specific ("undefined behavior") but there is no uninitialized memory.

                      > And a + b can invoke signed integer overflow UB. A program with more than zero UB cannot be considered memory safe.

                      No, memory safety is not undefined behavior. In fact Rust also silently allows signed integer overflow.

                      Remember, the reason memory safety is important is because it allows for untrusted code execution. Importantly here, even if you ignore scanf errors and integer overflow, this program accesses no memory that is not stack local. Now if one of these variables was cast into a pointer and used to index into a non-bounds-checked array then yes that would be memory unsafety. But the bigger code smell there is to cast an index into a pointer without doing any bounds checking.

                      That's sort of what storing indexes separately from references in a lot of Rust structures is doing inadvertently. It's validating accesses into a structure.

                • dayvster a day ago ago

                  har har... have my upvote!

              • zanellato19 a day ago ago

                I wasn't trying to be a dick, I am saying that my experience is that no big C program is ever safe. You replied that it is possible and I asked for an example. Providing a small script to prove that big C programs are safe isn't enough.

                • dayvster a day ago ago

                  Making a broad statement like there has never been a memory safe C program is a bit of a dickish thing to say.

                  especially when you phrase it as

                  > Can you provide examples for it? Because it honestly doesn't seem like it has ever been done.

                  it comes off as pedantic and arrogant.

                  It obviously is possible to write memory safe software in C and obviously it has been done before otherwise we would not be currently communicating over the goddamn internet.

                  Asking for evidence of something this obvious is akin to asking for a source on if water is in fact wet.

                  • zelphirkalt 18 hours ago ago

                    It's not dickish, and it's weird you seem to feel attacked/offended by that. It is a realistic conclusion, that we have come to over the course of decades of C usage. One could call it wisdom or collective learning.

                  • zanellato19 a day ago ago

                    I think pretty much any non trivial C example has memory safety issues. It doesn't mean that they aren't useful and can't be used. But time and time again we have seen security reports that point to memory issues. So no, I don't think I'm asking for something obvious, quite the contrary. I think the claim that it's possible to write big C programs that are memory safe is really strong and I heavily disagree with it.

                  • ksec a day ago ago

                    >> Can you provide examples for it? Because it honestly doesn't seem like it has ever been done.

                    >it comes off as pedantic and arrogant.

                    Interesting the way this was perceived. I thought he was just asking a honest question.

                    Again shows online discussion and communication is hard.

      • anon-3988 2 days ago ago

        I would argue that good C or C++ code is actually just Rust code with extra steps. So in this sense, Rust gets you to the "desired result" much easier compared to using C or C++ because no one is there to enforce anything and make you do it.

        You can argue that using C or C++ can get you to 80% of the way but most people don't actively think "okay, how do I REALLY mess up this program?" and fix all the various invariant that they forgot to handle. Even worse, this issue is endemic in higher level dynamic languages like Python too. Most people most of the time only think about the happy path.

        • wolvesechoes a day ago ago

          There are valid and safe programs rejected by Rust compiler if you don't go through rituals required to please it (slaping Rc, Refcells etc). No amount of "oh your Rust code is actually something you would ended up with if you would choose C" will change that.

          • simonask a day ago ago

            You know, the `unsafe` keyword exists. You’re allowed to use it. If your algorithm is truly safe, and as you say, there are many safe things the borrow checker cannot verify, that’s exactly what `unsafe` is for.

            Ideally you can also design a safe API around it using the appropriate language primitives to model the abstraction, but there’s no requirement.

          • crote a day ago ago

            Of course. After all, it is mathematically impossible to prove the correctness of all valid and safe programs - the halting problem clearly shows that. The real question should not be "Are there valid and safe programs Rust will reject?" but "How common is it that your well-written valid and safe program will be rejected by the Rust compiler?".

            In practice the vast majority will be accepted, and what remains is stuff the Rust compiler cannot prove to be correct. If Rust doesn't like your code, there are two solutions. The first is to go through the rituals to rewrite it as provably-safe code - which can indeed feel a bit tedious if your code was designed using principles which don't map well to Rust. The second is to use `unsafe` blocks - but that means proving its safety is up to the programmer. But as we've historically seen with C and unsafe-heavy Rust code bases, programmers are horrible at proving safety, so your mileage may vary.

            I don't want to be the "you're holding it wrong" person, but "Rust rejected my valid and safe program" more often than not means "there's a subtle bug in my program I am not aware of yet". The Rust borrow checker has matured a lot since its initial release, and it doesn't have any trouble handling the low-hanging fruit anymore. What's left is mainly complex and hard-to-reason-about stuff, and that's exactly the kind of code humans struggle with as well.

        • oconnor663 a day ago ago

          I think "writing Rust in C++" so to speak means at least two distinctly different things, which are both important. The first thing is that, as an individual programmer, you're being disciplined with memory and thinking about who owns what. The second thing is that as a group of programmers (over time), you all agree about who owns what. There are a lot of ways to learn the first thing, but I'm not sure there are a lot of ways to accomplish the second thing in a large system.

        • vanderZwan a day ago ago

          What does that have to do with Zig though?

      • rstuart4133 a day ago ago

        > The Rust community should be upfront about this tradeoff - it's a universal tradeoff, that is: Safety is less ergonomic.

        That can be true for small programs. Not always, because Rust's type system makes for programs that can be every bit as compact as Python if the algorithm doesn't interact badly with the borrow checker. Or even if it does. For example this tutorial converts a fairly nary C program to Rust: https://cliffle.com/p/dangerust/ The C was 234 lines, the finished memory safe Rust 198 lines.

        But when it comes to large programs, the ergonomics strangely tips into reverse. By "strangely tips into reverse", I mean yes it takes more tokens and thinking to produce a working Rust program, but overall it saves time. Here a "large program" means a programmer can't fit it all in his head at one time. I think Andrew Huang summed the effect up best, when he said if you start pulling on a thread in a Rust program, you always get to the end. In other languages, you often just make the knot tighter.

      • nicoburns a day ago ago

        > The Rust community should be upfront about this tradeoff - it's a universal tradeoff, that is: Safety is less ergonomic.

        I'd agree with that if the comparison is JavaScript or Python. If the comparison is Zig (or C or C++) then I don't agree that it's universal. I personally find Rust more ergonomic than those languages (in addition to be being safer).

      • thinkharderdev a day ago ago

        > As long as the audience accepts the framing that ergonomics doesn't matter because it can't be quantified, the hand-waving exemplified above will confound.

        I interpreted the parent to be saying that ergonomics IS (at least partly) subjective. The subjective aspect is "what you are used to". And once you get used to Rust its ergonomics are fine, something I agree with having used Rust for a few years now.

        > The Rust community should be upfront about this tradeoff

        I think they are. But more to the point, I think that safety is not really something you can reasonably "trade-off", at least not for non-toy software. And I think that because I don't really see C/C++/Zig people saying "we're trading off safety for developer productivity/performance/etc". I see them saying "we can write safe code in an unsafe language by being really careful and having a good process". Maybe they're right, but I'm skeptical based on the never-ending proliferation of memory safety issues in C/C++ code.

        • mattwilsonn888 a day ago ago

          I think you are clearly good-faith.

          The issue is the underlying and unfair assumption that is so common in these debates: that the memory-unsafe language we're comparing against Rust is always C/C++, rather than a modern approach like Zig or Odin (which will share many arguments against C/C++).

          You can prove to yourself this happens by looking around this thread! The topic is Zig vs. Rust and just look at how many pro-Rust arguments mention C (including yours).

          It's a strong argument if we pose C as the opponent, because C can be so un-ergonomic that even Rust with its added constraints competes on that aspect. But compare it to something like Zig or Odin (which has ergonomic and safety features like passing allocators to any and all functions, bounds checking by default, sane slice semantics which preclude the need for pointer arithmetic) and the ergonomics/safety argument isn't so simple.

          • tialaramex a day ago ago

            The ergonomics of Odin are ghastly, it's all special cases all the time.

            For example, in Rust when we write `for n in 0..10 {` that 0..10 is a Range, we can make one of those, we can store one in a variable, Range is a type. In Odin `for i in 0..<10 {` is uh, magic, we can't have a 0..<10, it's just syntax for the loop.

            in Rust we can `for puppy in litter {` and litter - whatever type that is - just has to implement IntoIterator, the trait for things which know how to be iterated, and they iterate over whatever that iterator does. In Odin only specific built-in types are suitable, and they do... whatever seemed reasonable to Bill.

            You can't provide this for your own type, it's a second class citizen and isn't given the same privileges as Odin's built-in types.

            If you're Ginger Bill, Odin is great, it does exactly what you expected and it covers everything you care about but nothing more.

            • mattwilsonn888 11 hours ago ago

              It's called simplicity.

              Not every single semantic element in the language needs to be a type.

              `for i in 0..<10`

              This isn't "magic," it's a loop that initializes a value `i` and checks against it. It's a lot less "magic" than Rust. The iterable types in Odin are slices and arrays - that is hardly arbitrary like you imply.

              The type system in Rust is mostly useful for its static guarantees. Using it for type-gymnastics and unnecessary abstractions is ugly and performative.

              Tasks in Odin can be accomplished with simplicity.

              The C++ misdirection and unbounded type abstractions are simply not appreciated by many.

              If you want a language with no special cases that is 100% fully abstract then program in a Turing machine. I'll take the language designed to make computers perform actions over a language having an identity crisis with mathematics research, all else equal. Unless I'm doing math research of course - Haskell can be quite fun!

              Ginger Bill is a PhD physicist as well -- not that education confers wisdom -- but I don't bet his design choices are coming from a resentment of math or abstraction.

              Absolute generality isn't the boon you think it is.

              • tialaramex 9 hours ago ago

                The "simplicity" you're so happy about means you only get whatever it is Bill made. If that doesn't work for Bill he'll fix it, but if it doesn't work for you (and at scale, it won't) too bad.

                Far from just the two special cases you listed I count five, Bill has found need for iterating over:

                Both built-in array types, strings (but not cstrings), slices and maps.

                `for a, b in c { ... }` makes a the key and b the value if c is a map, but if c were instead an array then a is the value and b is an index. Presumably both these ideas were useful to Bill and the lack of coherence didn't bother him.

                Maps are a particularly interesting choice of built-in. We could argue about exactly how a built-in string type should best work, or the growth policy for a mediocre growable array type - and Odin offers two approaches for strings (though not with the same support), but for maps you clearly need implementation options. and instead in the name of "simplicity" Bill locks you into his choice.

                You're stuck with Bill's choice of hash, Bill's layout, and Bill's semantics. If you want your own "hash table" type that's not map yours will have even worse ergonomics and you can't fix it. Yours can't be iterated with a for loop, it can't be special case initialized even if your users enabled that for the built-in type, and of course all the familiar functions and function groups don't work for your type.

                I don't have a use for a "language designed to make computers perform actions" when it lacks the fine control needed to get the best out of the machine but insists I must put in all the hard work anyway.

          • simonask a day ago ago

            Zig is an immense improvement, but it’s not a production language at the time of writing. Not a lot of people feel qualified to actually compare the two.

            At the same time, I will argue that Zig’s improvements over C are much less substantial compared to something like Rust. It’s great, but not a paradigm shift.

          • ksec a day ago ago

            Thank You that makes a lot of sense. I guess we will have to wait for Zig to become 1.0 first and then do a proper comparison.

      • weinzierl a day ago ago

        "It's true when you ride a skateboard with a helmet on."

        Rust is not the helmet. It is not a safety net that only gives you a benefit in rare catastrophic events.

        Rust is your lane assist. It relieves you from the burden of constant vigilance.

        A C or C++ programmer that doesn't feel relief when writing Rust has never acquired the mindset that is required to produce safe, secure and reliable code.

        • omnicognate a day ago ago

          Public Safety Announcement: Lane assist does not relieve you from the burden of constant vigilance.

        • travisgriggs a day ago ago

          > Rust is your lane assist. It relieves you from the burden of constant vigilance.

          Interesting analogy. I love lane assist. When I love it. And hate it when it gets in the way. It can actively jerk the car in weird and surprising ways when presented with things it doesn’t cope well with. So I manage when it’s active very proactively. Rust of course has unsafe… but… to keep the analogy, that would be like driving in a peer group where everyone was always asking me if I had my lane assist on, where when I arrived at a destination, I was badgered with “did you do the whole drive with lane assist?” And if I didn’t, I’d have explained to me the routes and techniques I could have used to arrive at my destination using used lane assist the whole way.

          Disclaimer, I have only dabbled a little with rust. It is the religion behind and around it that I struggle with, not the borrow checker.

          • danudey a day ago ago

            I have also mostly only dabbled with Rust, and I've come to the conclusion that it is a fantastic language for a lot of things but it is very unforgiving.

            The optimal way to write Python is to have your code properly structured, but you can just puke a bunch of syntax into a .py file and it'll still run. You can experiment with a file that consists entirely of "print('Hello World')" and go from there. Import a json file with `json.load(open(filename))` and boom.

            Rust, meanwhile, will not let you do this. It requires you to write a lot of best-practice stuff from the start. Loading a JSON file in a function? That function owns that new data structure, you can't just keep it around. You want to keep it around? Okay, you need to do all this work. What's that? Now you need to specify a lifetime for the variable? What does that mean? How do I do that? What do I decide?

            This makes Rust feel much less approachable and I think gives people a worse impression of it at the start when they start being told that they're doing it wrong - even though, from an objective memory-safety perspective, they are, it's still frustrating when you feel as though you have to learn everything to do anything. Especially in the context of the small programs you write when you're learning a language. I don't care about the 'lifetime' of this data structure if the program I'm writing is only going to run for 350ms.

            As I've toiled a bit more with Rust on small projects (mine or others') I feel the negative impacts of the language's restrictions far more than I feel the positive impacts, but it is nice to know that my small "download a URL from the internet" tool isn't going to suffer from a memory safety bug and rootkit my laptop because of a maliciously crafted URL. I'm sure it has lots of other bugs waiting to be found, but at least it's not those ones.

            • fpoling a day ago ago

              Rust is very forgiving if the goal is not the absolutely best performance. One can rewrite Python code into Rust mostly automatically and the end result is not bad. Recent LLMs can do it without complex prompting.

              The only problem is the code would be littered with Rc<RefCell<Foo>>. If Rust would have a compact notation for that a lot of pain related to fighting the borrow checker just to avoid the above would be eliminated.

              • wffurr a day ago ago

                >> If Rust would have a compact notation for "Rc<RefCell<Foo>>"

                That sounds like Rhai or one of the other Rust-alike scripting languages.

            • yen223 a day ago ago

              Someone (Rich Hickey?) described this as a piano that doesn't make a sound until you play the piece perfectly, and that analogy has stuck with me since.

              • timschmidt 7 hours ago ago

                Much preferred over pianos which are making unwanted sounds, unexpected sounds, loud crashing sounds, sounds initiated by sheet music which exploits a flaw in the piano's construction, and can therefore not be depended upon to sound appropriately during important events like concerts.

                That said, I'm all the time noodling new small programs in Rust. Cargo and crates.io makes this far simpler than with C/C++ where I have to write some code in another language entirely like [C]Make to get the thing to build. And I find that the borrow checker and rustc's helpful errors create a sort of ladder where all I have to do to get a working program is fix the errors the compiler identifies. And it often tells he how. Once the errors are fixed one by one, which is easy enough, and the software builds, my experience is that I get the expected program behavior about 95% of the time. I cannot say the same for other languages.

        • 6P58r3MXJSLi 20 hours ago ago

          > It relieves you from the burden of constant vigilance

          Is it..?

          Rust is more like your parents when you are a kid: don't do that, don't do that either! see? you wanted to go out to play with your friends and now you have a bruised knee. What did I told you? Now go to your room and stay there!

        • mattwilsonn888 a day ago ago

          No. It is not an invisible safeguard - it yaps and significantly increases compile time and (a matter of great debate) development effort.

          It is a helmet, just accept it. Helmets are useful.

          • steveklabnik a day ago ago

            The borrow checker is never a significant portion of compile times.

            • mattwilsonn888 a day ago ago

              This is incredibly misleading (technically true maybe) and you know it. Rust has slower compile times for the sake of safety, it's a tradeoff you shouldn't be ashamed of.

              I didn't narrowly claim the borrow checker (as opposed to the type system or other static analysis) was the sole focus of the tradeoff.

              • shakow a day ago ago

                > Rust has slower compile times

                That's true.

                > for the sake of safety,

                That's false though. All deep dives in the topic find that the core issue is the sheer amount of unoptimized IR that is thrown at LLVM, especially due to the pervasive monomorphization of everything.

                • mattwilsonn888 a day ago ago

                  Well it is arguably Rust's worst issue and it has remained it for most of its life.

                  Are you really going to try and convince people that this is completely incidental and not a result of pursuing its robust static contracts? How pedantic should we about about it?

                  • burntsushi 10 hours ago ago

                    On the one hand, you talk about being upfront and honest about trade-offs. On the other, you yourself are being less that credible by phrasing wild speculation as if they are facts.

                    So... do I as I say, not as I do?

                  • steveklabnik a day ago ago

                    Yes. This is borne out by the numbers. It has nothing to do with being pedantic, it’s basic facts.

                  • purplesyringa a day ago ago

                    It's not about static contracts at all, it's about keeping performance of high-level APIs high. It's all just about templates and generics, as far as I'm aware -- the same problem that plagues C++, except that it's worse in Rust because it's more ergonomic to expose templates in public library APIs in Rust than C++. Well, and also the trait solver might be quite slow, but again, it has nothing to do with memory safety.

                  • shakow 21 hours ago ago

                    > Are you really going to try and convince people that this is completely incidental and not a result of pursuing its robust static contracts?

                    I am, because that's what all the people that explored the question converged on.

                    Now if you have other evidences to bring to the debate, feel free to – otherwise, please stop spreading FUD and/or incompetence.

          • rowanG077 a day ago ago

            It is a helmet. But at least it's a helmet in situations where you get into brain cracking accidents multiple times a day. In the end the helmet allows you to get back up and continue your journey compared to when you had no helmet.

            • mattwilsonn888 a day ago ago

              We're talking about Zig not C. Same argument will apply to Odin.

              These modern approaches are not languages that result in constant memory-safety issues like you imply.

              • pjmlp 20 hours ago ago

                Modern as in 1978 and Modula-2 was just made available.

                Or better yet, modern as 1961 Burroughs released ESPOL/NEWP and C was a decade away to be invented.

        • nsagent a day ago ago

          I don't think this is any better of an argument.

          Maybe yours is a more apt analogy, but as a very competent driver I can't tell you how often lane assist has driven me crazy.

          If I could simply rely on it in all situations, then it would be fine. It's the death of a thousand cuts each and every time it behaves less than ideally that gets to me and I've had to turn it off in every single car a I've driven that has it.

      • spoiler 4 hours ago ago

        I find Rust more ergonomic than something like C or C++, or even Go.

        I feel unburdened while using Rust, which is not something I can say about a lot of other dev environments.

        As for Zig... I tried to get into it, and I can't remember the specifics, but they felt like "poor" taste in language design (I have a similar opinion of Go). I say taste because I think some thighs weren't necessarily bad, but I just couldn't convince myself to like them. I realise this is a very minority opinion, and I know great engineers who love Zig.

        Zig's just not my thing I guess. Same way Rust isn't someone else's thing.

      • aw1621107 a day ago ago

        > it's a universal tradeoff, that is: Safety is less ergonomic.

        I'm not sure that that tradeoff is quite so universal. GC'd languages (or even GC'd implementations like Fil-C) are equally or even more memory-safe than Rust but aren't necessarily any less ergonomic. If anything, it's not an uncommon position that GC'd languages are more ergonomic since they don't forbid some useful patterns that are difficult or impossible to express in safe Rust.

        • nextaccountic 15 hours ago ago

          GCed languages aren't (usually) more memory safe than safe Rust because they (usually) lack the equivalent to the Send and Sync traits and thus will not prevent unsynchronized access to the same from multiple threads, including data races. Some languages might define data races to not be UB (at least Java and OCaml do this, but Go famously doesn't), but even in those languages data races may produce garbage data due to tearing (writing to a large struct needs to be done in many steps, and without proper synchronization two concurrent updates may interleave leaving data structures in an inconsistent state)

          Guaranteed thread safety is huge. I hope more high level, GC languages use Rust's approach of defining an interface for types that can be safely sent and/or shared across threads

          • aw1621107 10 hours ago ago

            > GCed languages aren't (usually) more memory safe than safe Rust because they (usually) lack the equivalent to the Send and Sync traits and thus will not prevent unsynchronized access to the same from multiple threads, including data races.

            To be honest that particular aspect of Rust's memory safety story slipped my mind when I wrote that comment. I was thinking of Java's upcoming (?) disabling-by-default of sun.misc.Unsafe which allows you to ensure that you have no unsafe code at all in your program and your dependency tree outside of the JVM itself. To be fair, that's admittedly not quite the same level of memory safety improvement over Rust as Rust/Java/C#/etc. over C/C++/etc., but I felt it's a nice guarantee to have available.

            > Guaranteed thread safety is huge.

            I totally agree! It's not the only way to get memory safety, but I definitely lean towards that approach over defining data races to be safe.

        • SkiFire13 a day ago ago

          The tradeoff is between performance, safety and ergonomics. With GC languages you lose the first one.

          • quotemstr a day ago ago

            > The tradeoff is between performance, safety and ergonomics. With GC languages you lose the first one.

            That's a myth that just won't die. How is it that people simultaneously believe

            1) GC makes a language slow, and

            2) Go is fast?

            Go's also isn't the only safe GC. There are plenty of good options out there. You are unlikely to encounter a performance issue using one of these languages that you could resolve only with manual memory management.

            • shakow a day ago ago

              Go is not fast though.

              It's plenty fast compared to commonly used languages such as JS, PHP or Python, but can easily be let in the dust by Java and C#, which arguably play in the same court.

              And AOT-compiled, no GC languages like C++, Rust or Zig just run circles around it.

              • pjmlp 20 hours ago ago

                Not quite true if using GCC Go as compiler, however they seem to have dropped development after Go got generics.

                You are comparing quality of implementation, not languages.

                • shakow 19 hours ago ago

                  > You are comparing quality of implementation, not languages.

                  But comparing languages in a vacuum has 0 value. Maybe some alien entity will use physic transcending time and space to make TCL the fastest language ever, but right now I won't be writing heavy data-processing code in it.

                  • pjmlp 19 hours ago ago

                    At the same time, comparing without acknowledging that it is an implemenation issue, it is also not being fully honest.

                    For example, comparing languages with LLVM based implementations, usually if the machine code isn't the same, reveals that they aren't pushing the same LLVM IR down the pipe, and has little value for what the grammar actually looks like.

                    • shakow 19 hours ago ago

                      > comparing without acknowledging that it is an implemenation issue

                      Because that's implicit at this point – I'm not going to prefix with “because Earth geometry is approximately Euclidian at our scale” every time I'm telling a tourist to go straight ahead for 300m to their bus station.

                      Just like when people say “C++ is fast”, of course they refer to clang/g++/msvc, not some educational university compiler.

                      • pjmlp 17 hours ago ago

                        I seriously doubt it, given how many discussions go on HN or similar sites, revealing a complete lack of knowledge in compiler design.

                        Of course the authors of many of such comments aren't to blame, they only know what they know, hence why https://xkcd.com/386/

            • somanyphotons 11 hours ago ago

              Go is middle-pack fast, not fast-fast.

              There are always going to be problem sets where the GC causes significant slowdown.

            • cheshire_cat a day ago ago

              Go is fast compared to Python or Ruby. Go is not fast compared to C.

              I think people that talk about GC'd languages being slow are usually not building Rails or Django apps in their day to day.

              • on_the_beach a day ago ago

                Not a Go programmer I'm guessing.

                Go can be made to run much faster than C.

                Especially when the legacy C code is complex and thus single threaded, Go's fabulous multicore support means you can be exploiting parallelism and finishing jobs faster, with far less effort than it would take to do it in C.

                If you measure performance per developer day invested in writing the Go, Go usually wins by a wide margin.

                • quotemstr a day ago ago

                  > Go can be made to run much faster than C.

                  Not literally the case.

                  > If you measure performance per developer day invested in writing the Go, Go usually wins by a wide margin.

                  I can accept that performance/hour-spent is better in Go than C, but that's different from Go's performance ceiling being higher than C's. People often confuse ceilings with effort curves.

            • rixed a day ago ago

              > How is it that people simultaneously believe > 1) GC makes a language slow, and > 2) Go is fast?

              Easy one: either not the same people, or people holding self contradicting thoughts.

              GC are slow not only because of scanning the memory but also because of the boxing. In my experience, 2 to 3 times slower.

              Still a better tradeoff in the vast majority of cases over manual memory management. A GC is well worth the peace of mind.

              • quotemstr a day ago ago

                > also because of the boxing

                Not every GC boxes primitives. Most don't.

                • rixed a day ago ago

                  Sure. What about non primitives?

                  • pjmlp 20 hours ago ago

                    CLU, Cedar, Modula-2+, Modula-3, Oberon, Oberon-2, Oberon-07, Active Oberon, Component Pascal, Eiffel, Sather, BETA, D, Nim, Swift, C#, F# are all examples of GC based languages with value types that can be used without any kind of boxing.

                    • rixed 16 hours ago ago

                      Impressive erudition and interresting list of nice languages, some of which I'd never heard about, thank you. Yes indeed not all GCed languages suffer from mandatory boxing. I've been both picky and wrong, which is not a nice place to find oneself in :)

        • mattwilsonn888 a day ago ago

          *Under the assumption that you are maximizing both. I often hear complaints that Rust's semantics actually haven't maximized ergonomics, even factoring in the added difficulty it faces in pursuit of safety.

          It's totally possible languages as ergonomic as Rust can be more safe, just because Rust isn't perfect or even has some notable, partially subjective, design flaws.

          • aw1621107 a day ago ago

            > Under the assumption that you are maximizing both.

            I'm not sure that changes anything about my comment? GC'd languages can give you safety and* ergonomics, no need to trade off one for the other. Obviously doing so requires tradeoffs of their own, but such additional criteria were not mentioned in the comment I originally replied to.

            > I often hear complaints that Rust's semantics actually haven't maximized ergonomics, even factoring in the added difficulty it faces in pursuit of safety.

            Well yes, that's factually true. I don't think anyone can disagree that there aren't places where Rust can further improve ergonomics (e.g., partial borrows). And that's not even taking into account places where Rust intentionally made things less ergonomic (around raw pointers IIRC, though I think there's some discussion about changing that).

            > It's totally possible languages as ergonomic as Rust can be more safe

            It's definitely possible (see above about GC'd languages). There are just other tradeoffs that need to be made that aren't on the ergonomics <-> safety axis.

            • mattwilsonn888 a day ago ago

              Your earlier point that languages exist that are safer than Rust but not less ergonomic is irrelevant - that's the point I made.

              One can fail, or artificially make a language less ergonomic and that doesn't mean that fixing that somehow has an effect on the safety tradeoff.

              So obviously it is when safety and ergonomics are each already maximized that pushing one or the other results in a tradeoff. It's like saying removing weight from a car isn't a tradeoff because the weight was bricks in the trunk.

              Anyways I was holding performance constant in all of this because the underlying assumption of Rust and Zig and Odin and C is that performance will make no sacrifices.

              • aw1621107 21 hours ago ago

                > that's the point I made.

                That's not the way I read your original comment. When you said "it's a universal tradeoff, that is: Safety is less ergonomic", to me the implication is that gaining safety must result in losing ergonomics and vice versa. The existence of languages that are as safe/safer than Rust and more ergonomic than Rust would seem to be a natural counterexample since they have gained safety over Zig/C/C++ and haven't (necessarily, depending on the exact language) sacrificed ergonomics to do so.

                > One can fail, or artificially make a language less ergonomic and that doesn't mean that fixing that somehow has an effect on the safety tradeoff.

                To be honest that case didn't even cross my mind when I wrote my original comment. I was assuming we were working at the appropriate Pareto frontier.

                > So obviously it is when safety and ergonomics are each already maximized that pushing one or the other results in a tradeoff.

                Assuming no other relevant axes are available, sure.

                > Anyways I was holding performance constant in all of this because the underlying assumption of Rust and Zig and Odin and C is that performance will make no sacrifices.

                Sure. Might have been nice to include that assumption in your original comment, but even then I'm not sure it's too wise to ignore the performance axis completely due to the existence of safe implementations of otherwise "unsafe" languages (e.g., Zig's ReleaseSafe, GCs for C like Fil-C, etc.) that trade off performance for safety instead of ergonomics.

      • pjmlp a day ago ago

        As I mention elsewhere, C crowd didn't call languages like Pascal and Modula-2 programming with straightjacket for no reason.

        Turns out not wearing that helmet, and continously falling down for 40 years at the skate park has its price.

      • junon 19 hours ago ago

        Writing rust fulltime for my personal projects, I have to disagree that Rust isn't ergonomic.

        In fact, I find it more ergonomic than any other language I ever work with. I'm consistently more productive with it than even scripting languages.

        Getting tired of this quip being asserted as fact. Ergonomics are subjective; memory safety is not.

        • player1234 18 hours ago ago

          How did you measure this productivity boost? Please share your results and methodology.

          • junon 15 hours ago ago

            How did you measure the assertion that Rust is not ergonomic? Please share your results and methodology.

      • freeopinion a day ago ago

        Arguing that one language is more ergonomic but can produce the same safety if you use it unergonomically is... not very useful in a context where safety is highly valued.

      • bionhoward a day ago ago

        Rust feels easy for me, could it be we’re just used to what we use more?

        Anyway, it’s all pretty easy, what’s the use arguing which of multiple easy things is easiest?

      • charcircuit a day ago ago

        >Safety is less ergonomic.

        It's not safety that makes it less ergonomic, it's correctness.

        • mattwilsonn888 a day ago ago

          Implying that correctness necessitates a lack of ergonomics is deeply flawed.

          The distinction between correctness and safety is that safety is willing to suffer false positives, in pursuit of correctness. Correctness is just correctness.

          • charcircuit a day ago ago

            It's not flawed. Ergonomics are correlated with complexity. If you can remove edge cases by giving up on correctness you can remove complexity.

      • timeon a day ago ago

        How are chairs related to programming languages? Analogies are just made-up arguments.

        • mattwilsonn888 a day ago ago

          Because a primary function of the chair is the same to programming languages: ergonomics.

          That is obviously true, otherwise we'd code in assembly and type in UTF-8 byte codes.

      • SoraNoTenshi a day ago ago

        It also drives me insane when i dump the problems i have with Rust about this exact issue, that i usually have to restructure my code to satisfy the compilers needs, and they come at me with the "Skill Issue" club...

        I honestly don't even know what to respond to that, but it's kind of weird to me to honestly think that you'd need essentially a "PhD" in order to use a tool...

        • mattwilsonn888 a day ago ago

          It's an amazing piece of marketing to corner anyone who dislikes a certain hassle as being mentally deficient - that's what "skill issue" means in this context.

          • shakow a day ago ago

            > that's what "skill issue" means in this context.

            “Skill issue” definitely does not means “mentally deficient”. It comes from the videogames world, where it is used to disparage the lack of training/natural ability of other players; frequently accompanied by “get good”, i.e. continue training & grinding to up your skill.

            • mattwilsonn888 10 hours ago ago

              Do I have to put the pieces together for you? What is the relevant skill in programming? Problem solving. It's not aim or timing or hand-eye coordination lmao.

              • vrmiguel 9 hours ago ago

                Not sure I get your point. One can definitely "get good" at problem solving. Isn't that the whole purpose of Leetcode and whatnot?

                I struggled with Rust at first but now it feels quite natural, and is the language I use at work and for my open-source work.

                I was not "mentally deficient" when I struggled with Rust (at least that I know of :v), while you could say I had a skill issue with the language

        • Ar-Curunir a day ago ago

          Not saying that Rust is necessarily easy to pick up, but hundreds of thousands of people use Rust without a PhD in any subject.

          • mattwilsonn888 a day ago ago

            Try and appreciate the humor in what you're replying to without fully discounting the point of it.

          • SoraNoTenshi 17 hours ago ago

            It is of course an exaggeration, but that's what is somewhat annoying to me. But dismissing this point by just saying me "get better" after literally years of using Rust is a bit of a weak point, or am i in the wrong here?

            And it's not even that i dislike the language, but this is evangelism to just dismiss the point of my argument with "skill issue". A tool isn't supposed to be difficult, it should help you in whatever you're trying to achieve, not making it more difficult.

          • a day ago ago
            [deleted]
      • dayvster a day ago ago

        > The Rust community should be upfront about this tradeoff - it's a universal tradeoff, that is: Safety is less ergonomic. It's true when you ride a skateboard with a helmet on, it's true when you program, it's true for sex.

        Well put! And this should not be contentious issue, it simply is annoying to deal with Rust's very strict compiler. It's not a matter of opinion it simply is more annoying than if you were to use any other language that does not put that much burden on you the developer.

        Not all memory safety bugs are critical issues either. We like to pretend like they are but specifically in `coreutils` there were 2 memory safety bugs found recently.

        However is it really a big concern? if someone has gotten access to your system where they can run `coreutil` commands you probably have bigger problems than them running a couple of commands that leak.

        • aw1621107 a day ago ago

          > if someone has gotten access to your system where they can run `coreutil` commands you probably have bigger problems than them running a couple of commands that leak.

          Speaking more abstractly since I haven't looked at the CVEs in question, but an attacker directly accessing coreutils on your system isn't the only possible attack vector. Another potentially interesting one would be them expecting you to run coreutils on something under they control. For example, a hypothetical exploit in grep might be exploitable by getting you to grep through a repo with a malicious file.

          A more concrete example would be some of the various zero-click iMessage exploits, where the vulnerable software isn't exploited via the attackers directly accessing the victim's device but is exploited by sending a malicious file.

    • tialaramex 2 days ago ago

      > Seasoned Rust coders don’t spend time fighting the borrow checker

      I like the fact that "fighting the borrow checker" is an idea from the period when the borrowck only understood purely lexical lifetimes. So you have to fight to explain why the thing you wrote, which is obviously correct, is in fact correct.

      That's already ancient history by the time I learned Rust in 2021. But, this idea that Rust will mean "fighting the borrow checker" took off anyway even though the actual thing it's about was solved.

      Now for many people it really is a significant adjustment to learn Rust if your background is exclusively say, Python, or C, or Javascript. For me it came very naturally and most people will not have that experience. But even if you're a C programmer who has never had most of this [gestures expansively] before you likely are not often "fighting the borrow checker". That diagnostic saying you can't make a pointer via a spurious mutable reference? Not the borrow checker. The warning about failing to use the result of a function? Not the borrow checker.

      Now, "In Rust I had to read all the diagnostics to make my software compile" does sound less heroic than "battling with the borrow checker" but if that's really the situation maybe we need to come up with a braver way to express this.

      • Austizzle 2 days ago ago

        I think the phrase _emotionally_ resonates with people who write code that would work in other languages, but the compiler rejects.

        When I was learning rust (coming from python/java) it certainly felt like a battle because I "knew" the code was logically sound (at least in other languages) but it felt like I had to do all sorts of magic tricks to get it to compile. Since then I've adapted and understand better _why_ the compiler has those rules, but in the beginning it definitely felt like a fight and that the code _should_ work.

      • milch 12 hours ago ago

        I've heard lots of people complain during the "exploratory" phase of writing code - maybe you haven't fully figured out how to write the code yet, you're iteratively making changes and restructuring as you go. Most languages make this easy, but with Rust e.g. if you add a lifetime to a reference in a struct it usually becomes a major refactor which can be frustrating to deal with when you're not even sure yet if your approach will work. More experienced devs would probably just use Rc or similar in that case to avoid the lifetime, and then maybe go back and refactor later once the code is "solidified", but for newer devs - they add the &, see the compiler error telling them it's missing a lifetime annotation, spend 30min refactoring, and that's how these stereotypes get reinforced

      • zorked 18 hours ago ago

        Ah, thanks for the historical take. I learned Rust recently. I like it. I never fought the borrow checker. I was sometimes happily protected by the borrow checker. I never understood what people were talking about.

        • tialaramex 13 hours ago ago

          Right, in early Rust, years ago, it's not even legal to do this:

              fn main() {
                  let mut x = 5;
                  let y = &x;
                  let z = &mut x;
              }
          
          The original borrowck goes oh no, y is a reference to x and then z is a mutable reference to x, those can't both exist at the same time, but the scope of y hasn't ended so I give up here's an error message. You needed to adjust your software so that it can see why what you wrote is fine. That's "fighting the borrow checker".

          But today's borrowck just goes duh, the reference y goes away right before the variable z is created and everything is cool.

          These are called "Non-lexical lifetimes" because the lifetime is no longer strictly tied to a lexical scope - the curly braces in the program - but can have any necessary extent to make things correct.

          Further improving the ability of the borrowck to see that what you're doing is fine is an ongoing piece of work for Rust and always will be†, but NLL was the lowest hanging fruit, most of the software I write would need tweaks to account for a strict lexical lifetime and it'd be very annoying when I know I am correct.

          † Rice's theorem tells us we can either have a compiler where sometimes illegal borrows are allowed or a compiler where sometimes borrows that should be legal are forbidden (or both, which seems useless), but we cannot have one which is always right, so, Rust chooses the safe option and that means we're always going to be working to make it just a bit better.

    • Galanwe 2 days ago ago

      > Seasoned Rust coders don’t spend time fighting the borrow checker

      My experience is that what makes your statement true, is that _seasoned_ Rust developers just sprinkle `Arc` all over the place, thus effectively switching to automatic garbage collection. Because 1) statically checked memory management is too restrictive for most kinds of non trivial data structures, and 2) the hoops of lifetimes you have to go to to please the static checker whenever you start doing anything non trivial are just above human comprehension level.

      • hu3 2 days ago ago

        I did some quick search, not sure if this supports or denies your point:

        - 151 instances of "Arc<" in Servo: https://github.com/search?q=repo%3Aservo%2Fservo+Arc%3C&type...

        - 5 instances of "Arc<" in AWS SDK for Rust https://github.com/search?q=repo%3Arusoto%2Frusoto%20Arc%3C&...

        - 0 instances for "Arc<" in LOC https://github.com/search?q=repo%3Acgag%2Floc%20Arc%3C&type=...

      • andrewl-hn 2 days ago ago

        `Arc`s show up all over the place specifically in async code that targets Tokio runtime running in multithreaded mode. Mostly this is because `tokio::spawn` requires `Future`s to be `Send + 'static`, and this function is a building block of most libraries and frameworks built on top of Tokio.

        If you use Rust for web server backend code then yes, you see `Arc`s everywhere. Otherwise their use is pretty rare, even in large projects. Rust is somewhat unique in that regard, because most Rust code that is written is not really a web backend code.

        • khuey a day ago ago

          > `Arc`s show up all over the place specifically in async code that targets Tokio runtime running in multithreaded mode. Mostly this is because `tokio::spawn` requires `Future`s to be `Send + 'static`, and this function is a building block of most libraries and frameworks built on top of Tokio.

          To some extent this is unavoidable. Non-'static lifetimes correspond (roughly) to a location on the program stack. Since a Future that suspends can't reasonably stay on the stack it can't have a lifetime other than 'static. Once it has to be 'static, it can't borrow anything (that's not itself 'static), so you either have to Copy your data or Rc/Arc it. This, btw, is why even tokio's spawn_local has a 'static bound on the Future.

          It would be nice if it were ergonomic for library authors to push the decision about whether to use Rc<RefCell<T>> or Arc<Mutex<T>> (which are non-threadsafe and threadsafe variants of the same underlying concept) to the library consumer.

      • qw3rty01 2 days ago ago

        This is exactly the opposite of what he’s saying, using Arc everywhere is hacking around the borrow checker, a seasoned rust developer will structure their code in a way that works with the borrow checker; Arc has a very specific use case and a seasoned rust developer will rarely use it

        • Aurornis 2 days ago ago

          These extreme generalizations are not accurate, in my experience.

          There are some cases where someone new to Rust will try to use Arc as a solution to every problem, but I haven't seen much code like this outside of reviewing very junior Rust developers' code.

          In some application architectures Arc is a common feature and it's fine. Saying that seasoned Rust developers rarely use Arc isn't true, because some types of code require shared references with Arc. There is nothing wrong with Arc when used properly.

          I think this is less confusing to people who came from modern C++ and understand how modern C++ features like shared_ptr work and when to use them. For people coming from garbage collected languages it's more tempting to reach for the Arc types to try to write code as if it was garbage collected.

        • packetlost 2 days ago ago

          Arc<T> is all over the place if you're writing async code unfortunately. IMO Tokio using a work-stealing threaded scheduler by default and peppering literally everything with Send + Sync constraints was a huge misstep.

          • ekidd a day ago ago

            I mostly wind up using Arc a lot while using async streams. This tends to occur when emulating a Unix-pipeline-like architecture that also supports concurrency. Basically, "pipelines where we can process up to N items in parallel."

            But in this case, the data hiding behind the Arc is almost never mutable. It's typically some shared, read-only information that needs to live until all the concurrent workers are done using it. So this is very easy to reason about: Stick a single chunk of read-only data behind the reference count, and let it get reclaimed when the final worker disappears.

          • vlovich123 2 days ago ago

            Arc + work stealing scheduler is common. But work stealing schedulers are common (eg libdispatch popularized it). I believe the only alternative is thread-per core but they’re not very common/popular. For what it’s worth zig would look very similar except their novel injectable I/O syntax isn’t compatible with work stealing.

            Even then, I’d agree that while Arc is used in lots of places in work stealing runtimes, I disagree that it’s used everywhere or that you can really do anything else if you want to leverage all your cores with minimum effort and not having to build your application specialized to deal with that.

            • packetlost 2 days ago ago

              Being possible with minimal effort doesn't really preclude it from it not being the default. The issue I have is huge portions of Tokio's (and other async libs) API have a Send + Sync constraint that destroy the benefit of LocalSet / spawn_local. You can't build and application with the specialized thread-per core or single-threaded runtime thing if you wanted to because of pervasive incidental complexity.

              I don't care that they have a good work-stealing event loop, I care that it's the default and their APIs all expect the work-stealing implementation and unnecessarily constrain cases where you don't use that implementation. It's frustrating and I go out of my way to avoid Tokio because of it.

              Edit: the issues are in Axum, not the core Tokio API. Other libs have this problem too due to aforementioned defaults.

              • Arnavion a day ago ago

                >You can't build and application with the specialized thread-per core or single-threaded runtime thing if you wanted to because of pervasive incidental complexity. [...] It's frustrating and I go out of my way to avoid Tokio because of it.

                At $dayjob we have built a large codebase (high-throughput message broker) using the thread-per-core model with tokio (ie one worker thread per CPU, pinned to that CPU, driving a single-threaded tokio Runtime) and have not had any problems. Much of our async code is !Send or !Sync (Rc, RefCell, etc) precisely because we want it to benefit from not needing to run under the default tokio multi-threaded runtime.

                We don't use many external libs for async though, which is what seems to be the source of your problems. Mostly just tokio and futures-* crates.

                • packetlost a day ago ago

                  I might be misremembering and the overbearing constraints might be in Axum (which is still a Tokio project). External libs are a huge problem in this area in general, yeah.

              • vlovich123 a day ago ago

                Single-threaded runtime doesn't require Send+Sync for spawned futures. AFAIK Tokio doesn't have a thread-per-core backend and as a sibling intimated you could build it yourself (or use something more suited for thread-per-core like Monoio or Glommio).

        • jasonjmcghee 2 days ago ago

          This is awkward. I've written a fair amount of rust. I reach for Arc frequently. I see the memory layout implications now.

          Do you tend to use a lot of Arenas?

          • dminik a day ago ago

            I've not explored every program domain, but in general I see two kinds of program memory access patterns.

            The first is a fairly generic input -> transform -> output. This is your generic request handler for instance. You receive a payload, run some transform on that (and maybe a DB request) and then produce a response.

            In this model, Arc is very fitting for some shared (im)mutable state. Like DB connections, configuration and so on.

            The second pattern is something like: state + input -> transform -> new state. Eg. you're mutating your app state based on some input. This fits stuff like games, but also retained UIs, programming language interpreters and so on on.

            Using ARCs here muddles the ownership. The gamedev ecosystem has found a way to manage this by employing ECS, and while it can be overkill, the base DOD principles can still be very helpful.

            Treat your data as what it is; data. Use indices/keys instead of pointers to represent relations. Keep it simple.

            Arenas can definitely be a part of that solution.

        • bilekas 2 days ago ago

          This is something I have noticed while I'm by no means seasoned enough to consider myself even a mid level, some of my colleagues are and what they tend to do it plan ahead much better or pedantically, as they put it, the worst thing you will end up doing it's trying to change an architectural decision later on.

      • Aurornis 2 days ago ago

        > thus effectively switching to automatic garbage collection

        Arc isn't really garbage collection. It's like a reference counted smart pointer like C++ has shared_ptr.

        If you drop an Arc and it's the last reference to the underlying object, it gets dropped deterministically.

        Garbage collection generally refers to more complex systems that periodically identify and free unused objects in a less deterministic manner.

        • ninkendo a day ago ago

          Also importantly, an Arc<T> can be passed to anything expecting a &T, so you’re not necessarily bumping refcounts all over the place when using an Arc. If you only store it in one place, it’s basically equivalent to any other boxed pointer.

        • Arnavion a day ago ago

          >Garbage collection generally refers to more complex systems that periodically identify and free unused objects in a less deterministic manner.

          No, this is a subset of garbage collection called tracing garbage collection. "Garbage collection" absolutely includes refcounting.

          • simonask a day ago ago

            There’s just no good reason to conflate the two. Rust’s Arc and C++’s std::shared_ptr do not reclaim reference cycles, so you can call it “garbage collection” if you want, but the colloquial understanding is way more useful.

            • pjmlp 20 hours ago ago

              The coloquial term is like people arguing about coaching a footbal team without making it into the field.

              Chapter 5, https://gchandbook.org/contents.html

              Other CS quality references can be provided with similar table of contents.

        • hansvm a day ago ago

          That's fair. It's not really a good pattern though. You get all the runtime overhead of object-soup allocation patterns, syntactic noise making it harder to read than even a primitive GC language (including one using ARC by default and implementing deterministic dropping, a pattern most languages grow out of), and the ability to easily leak [0] memory because it's not a fully garbage-collected solution.

          As a rough approximation, if you're very heavy-handed with ARC then you probably shouldn't be using rust for that project.

          [0] The term "leak" can be a bit hard to pin down, but here I mean something like space which is allocated and which an ordinary developer would prefer to not have allocated.

          • Aurornis a day ago ago

            I agree that using an Arc where it's unnecessary is not good form.

            However, I disagree with generalizations that you can judge the quality of code based on whether or not it uses a lot of Arc. You need to understand the architecture and what's being accomplished.

            • hansvm a day ago ago

              > disagree with generalizations that you can judge the quality of code based on whether or not it uses a lot of Arc

              That wasn't really my point, but I disagree with your disagreement anyway ;) Yes, you don't want to over-generalize, but Arc has a lot of downsides, doesn't have a lot of upsides, and can usually be relatively easily avoided in lieu of something with a better set of tradeoffs. Heavy use isn't bad in its own right, but it's a strong signal suggestive of code needing some love and attention.

              My point though was: If you are going to heavily use Arc, Rust isn't the most ergonomic language for the task, and where for other memory management techniques the value proposition of Rust is more apparent it's a much narrower gap compared to those ergonomic choices if you use Arc a lot. Maybe you have to (or want to) use Rust anyway for some reason, but it's usually a bad choice conditioned on that coding style.

        • bluGill a day ago ago

          Reference counting has always been a way to garbage collect. Those who like garbage collection have always looked down on it because it cannot handle circular references and is typically slower than the mark and sweep garbage collectors they prefer.

          If you need a referecne counted garbage collector for more than a tiny minotiry of your code, then Rust was probably the wrong choice of language - use something that has a better (mark and sweep) garbage collectors. Rust is good for places where you can almost always find a single owner, and you can use reference counting for the rare exception.

          • Aurornis a day ago ago

            Reference counting can be used as an input to the garbage collector.

            However, the difference between Arc and a Garbage Collector is that the Arc does the cleanup at a deterministic point (when the last Arc is dropped) whereas a Garbage Collector is a separate thing that comes along and collects garbage later.

            > If you need a referecne counted garbage collector for more than a tiny minotiry of your code

            The purpose of Arc isn't to have a garbage collector. It's to provide shared ownership.

            There is no reason to avoid Rust if you have an architecture that requires shared ownership of something. These reductionist generalizations are not accurate.

            I think a lot of new Rust developers are taught that Arc shouldn't be abused, but they internalize it as "Arc is bad and must be avoided", which isn't true.

            • bluGill 15 hours ago ago

              > whereas a Garbage Collector is a separate thing that comes along and collects garbage later.

              That is the most common implementation, but that is still just an implementation detail. Garbage collectors can run deterministically which is what reference counting does.

              > There is no reason to avoid Rust if you have an architecture that requires shared ownership of something.

              Rust can be used for anything. However the goals are still something good for system programming. Systems programming implies some compromises which makes Rust not as good a choice for other types of programming. Nothing wrong with using it anyway (and often you have a mix and the overhead of multiple languages makes it worth using one even when another would be better for a small part of the problem)

              > I think a lot of new Rust developers are taught that Arc shouldn't be abused, but they internalize it as "Arc is bad and must be avoided", which isn't true.

              Arc has a place. However most places where you use it a little design work could eliminate the need. If you don't understand what I'm talking about then "Arch is bad and must be avoided" is better than putting Arc everywhere even though that would work and is less effort in the short run (and for non-systems programming it might even be a good design)

        • nayuki a day ago ago

          > Arc isn't really garbage collection. It's like a reference counted smart pointer

          Reference counting is a valid form of garbage collection. It is arguably the simplest form. https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...

          The other forms of GC are tracing followed by either sweeping or copying.

          > If you drop an Arc and it's the last reference to the underlying object, it gets dropped deterministically.

          Unless you have cycles, in which case the objects are not dropped. And then scanning for cyclic objects almost certainly takes place at a non-deterministic time, or never at all (and the memory is just leaked).

          > Garbage collection generally refers to more complex systems that periodically identify and free unused objects in a less deterministic manner.

          No. That's like saying "a car is a car; a vehicle is anything other than a car". No, GC encompasses reference counting, and GC can be deterministic or non-deterministic (asynchronous).

        • jcelerier a day ago ago

          > Arc isn't really garbage collection. It's like a reference counted smart pointer like C++ has shared_ptr.

          In c++ land this is very often called garbage collection too

        • jandrewrogers a day ago ago

          This still raises the question of why Arc is purportedly used so heavily. I've written 100s of kLoC of modern systems C++ and never needed std::shared_ptr.

          • pjmlp a day ago ago

            For the same reason Unreal uses one.

            Large scale teams always get pointer ownership wrong.

            Project Zero has enough examples.

      • steveklabnik 2 days ago ago

        The only time I use Arc is wrapping contexts for web handlers.

        That doesn’t mean there aren’t other legitimate use cases, but “all the time” is not representative of the code I read or write, personally.

      • kibwen 2 days ago ago

        > _seasoned_ Rust developers just sprinkle `Arc` all over the place

        No, this couldn't be further from the truth.

        • 9rx 2 days ago ago

          If they aren't sprinkling `Arc` all over, what are they seasoning with instead?

      • swiftcoder 2 days ago ago

        I don't think there are any Arcs in my codebase (apart from a couple of regrettable ones needed to interface with Javascript callbacks in WASM - this is more a WASM problem than a rust problem).

        • ChadNauseam 2 days ago ago

          haha, I was about to leave the exact same comment. how are you finding wasm? I’ve been feeling like rust+react is my new favorite tech stack

      • amw-zero 2 days ago ago

        How often are you writing non-trivial data structures?

      • kannanvijayan a day ago ago

        Not sure how seasoned I am, but I reject any comparison to a cooking utensil!

        I do find myself running into lifetime and borrow-checker issues much less these days when writing larger programs in rust. And while your comment is a bit cheeky, I think it gets at something real.

        One of the implicit design mentalities that develops once you write rust for a while is a good understanding of where to apply the `UnsafeCell`-related types, which includes `Arc` but also `Rc` and `RefCell` and `Cell`. These all relate to inner mutability, and there are many situations where plopping in the right one of these effectively resolves some design requirement.

        The other idiomatic thing that happens is that you implicitly begin structuring your abstract data layouts in terms of thunks of raw structured data and connections between them. This usually involves an indirection - i.e. you index into an array of things instead of holding a pointer to the thing.

        Lastly, where lifetimes do get involved, you tend to have a prior idea of what thing they annotate. The example in the article is a good case study of that. The author is parsing a `.notes` file and building some index of it. The text of the `.notes` file is the obvious lifetime anchor here.

        You would write your indexing logic with one lifetime 'src: `fn build_index<'src>(src: &'src str)`

        Internally to the indexing code, references to 'src-annotated things can generally pass around freely as their lifetime converges after it.

        Externally to the indexing code you'd build a string of the notes text, and passing a reference to that to the `build_index` function.

        For simple CLI programs, you tend not to really need anything more than this.

        It gets more hairy if you're looking at constructing complex object graphs with complex intermediate state, partial construction of sub-states, etc. Keeping track of state that's valid at some level, while temporarily broken at another level, is where it gets really annoying with multiple nested lifetimes and careful annotation required.

        But it was definitely a bit of a hair-pulling journey to get to my state of quasi-peace with Rust's borrow checker.

      • levkk 2 days ago ago

        Definitely not. Arc is for immutable (or sync, e.g. atomics, mutexes) data, while borrow checker protects against concurrent mutations. I think you meant Arc<Mutex<T>> everywhere, but that code smells immediately and seasoned Rust devs don't do that.

      • dev_l1x_be 2 days ago ago

        I am not sure this is true. Maybe with shared async access it is. I rarely use Arc.

      • bryanlarsen a day ago ago

        Or more likely, sprinkle .clone() liberally and Arc or an Arc wrapper (ArcSwap, tokio's watch channels, etc) strategically.

      • ViewTrick1002 18 hours ago ago

        > My experience is that what makes your statement true, is that _seasoned_ Rust developers just sprinkle `Arc` all over the place, thus effectively switching to automatic garbage collection.

        How else would you safely share data in multi-threaded code? Which is the only reason to use Atomic reference counts.

    • dayvster 2 days ago ago

      > Seasoned Rust coders don’t spend time fighting the borrow checker

      No true scotsman would ever be confused by the borrow checker.

      i've seen plenty of rust projects open source and otherwise that utilise Arc heavily or use clone and/or copy all over the place.

      • vrmiguel 9 hours ago ago

        Why would using Arc mean that someone is fighting the borrow checker, or confused by it?

        Would you also say the same for a C++ project that uses shared_ptrs everywhere?

        The clone quip doesn't work super well when comparing to C++ since that language "clones" data implicitly all the time

      • fkyoureadthedoc a day ago ago

        I'm starting to think No True HNer goes without misidentifying a No True Scotsman fallacy.

        They are clearly just saying as you become more proficient with X, Y is less of a problem. Not that if the borrow checker is blocking you that you aren't a real Rust programmer.

        Let's say you're trying to get into running. You express that you can't breathe well during the exercise and it's a miserable experience. One of your friends tells you that as an experienced runner they don't encounter that in the same way anymore, and running is thus more enjoyable. Do you start screeching No True Scotsman!! at them? I think not.

      • Ygg2 2 days ago ago

        > > Seasoned Rust coders don’t spend time fighting the borrow checker

        > No true scotsman would ever be confused by the borrow checker.

        I'd take that No true scotsman over the "Real C programmers write code without CVE" for $5000.

        Also you are strawmanning the argument. GP said, "As a seasoned veteran of Rust you learn to think like the borrow checkers." vs "Real Rust programmers were born with knowledge of borrow checker".

    • melodyogonna 2 days ago ago

      I believe the benefit of Zig is that it allows you the familiarity of writing code like in C, but has other elements in the language and tooling to make things safer. For example, Zig has optionals, which can eliminate nil deference. Another example is how you can pass some debug or custom allocators during testing that have all sorts of runtime checks to detect bad memory access and resource leaks.

      I have some issues with Zig's design, especially around the lack of explicit interface/trait, but I agree with the post that it is a more practical language, just because of how much simpler its adoption is.

    • dev_l1x_be 2 days ago ago

      I can't remember the last time I had any problem with the borrow checker. The junior solution is .clone(), better one is & (reference) and if you really need you can start to use <'a>. There is a mild annoyance with which function consumes what and the LLM era really helped with this.

      My beef is sometimes with the ways traits are implemented or how AWS implemented Errors for the their library that is just pure madness.

      • vlovich123 2 days ago ago

        > The junior solution is .clone()

        I really hope it’s an Rc/Arc that you’re cloning. Just deep cloning the value to get ownership is dangerous when you’re doing it blindly.

        • dev_l1x_be 14 hours ago ago

          Sure thing, this is why you need to learn what happens with copy and clone. Interestingly smaller problems are going to be ok even with clone(). The real value is to be able to spot potential performance optimizations by grep '(copy|clone)'.

          • vlovich123 14 hours ago ago

            How are you going to grep for copies? You know there’s no .copy method right?

      • seivan 2 days ago ago

        How did AWS mess up errors?

        • dev_l1x_be a day ago ago

          Maybe I am holding it wrong.

          Here is one piece of the problem:

            while let Some(page) = object_stream.next().await {
                  match page {
                      // ListObjectsV2Output
                      Ok(p) => {
                          if let Some(contents) = p.contents {
                              all_objects.extend(contents);
                          }
                      }
                      // SdkError<ListObjectsV2Error, Response>
                      Err(err) => {
                          let raw_response = &err.raw_response();
                          let service_error = &err.as_service_error();
                          error!("ListObjectsV2Error: {:?} {:?}", &service_error, &raw_response);
                          return Err(S3Error::Error(format!("ListObjectsV2Error: {:?}", err)));
                      }
                  }
              }
          • estebank a day ago ago

            Out of curiosity, why are you borrowing that many times? The following should work:

                while let Some(page) = object_stream.next().await {
                    match page {
                        // ListObjectsV2Output
                        Ok(p) => {
                            if let Some(contents) = p.contents {
                                all_objects.extend(contents);
                            }
                        }
                        // SdkError<ListObjectsV2Error, Response>
                        Err(err) => {
                            let raw_response = err.raw_response();
                            let service_error = err.as_service_error();
                            error!("ListObjectsV2Error: {:?} {:?}", service_error, raw_response);
                            return Err(S3Error::Error(format!("ListObjectsV2Error: {:?}", err)));
                        }
                    }
                }
            
            I would have written it this way

                while let Some(page) = object_stream.next().await {
                    let p: ListObjectsV2Output = page.map_err(|err| {
                        // SdkError<ListObjectsV2Error, Response>
                        let raw_response = err.raw_response();
                        let service_error = err.as_service_error();
                        error!("ListObjectsV2Error: {service_error:?} {raw_response:?}");
                        S3Error::Error(format!("ListObjectsV2Error: {err:?}"))
                    })?;
                    if let Some(contents) = p.contents {
                        all_objects.extend(contents);
                    }
                }
            
            although if your crate defines `S3Error`, then I would prefer to write

                while let Some(page) = object_stream.next().await {
                    if let Some(contents) = page?.contents {
                        all_objects.extend(contents);
                    }
                }
            
            by implementing `From`:

                impl From<SdkError<ListObjectsV2Error, Response>> for S3Error {
                    fn from(err: SdkError<ListObjectsV2Error, Response>) -> S3Error {
                        let raw_response = err.raw_response();
                        let service_error = err.as_service_error();
                        error!("ListObjectsV2Error: {service_error:?} {raw_response:?}");
                        S3Error::Error(format!("ListObjectsV2Error: {err:?}"))
                    }
                }
            • dev_l1x_be 16 hours ago ago

              Excellent! Thank you!

              My problem is that I should have something like

              (http_status, reason) where http_status is a String or u16, reason is a enum with SomeError(String) structure. So essentially having a flat meaningful structure instead of this what we currently have. I do not have any mental model about the error structure of the AWS libs or don't even know where to start to create that mental model. As a result I just try to turn everything to a string and return it altogether hoping that the real issue is there somwhere in that structure.

              I think the AWS library error handling is way to complex for what it does and one way we could improve that if Rust had a great example of a binary (bin) project that has lets say 2 layers of functions and showing how to organize your error effectively.

              Now do this for a lib project. Without this you end up with this hot mess. At least this is how I see it. If you have a suggestion how should I return errors from a util.rs that has s3_list_objects() to my http handler than I would love to hear what you have to say.

              Thanks for your suggestions anyway! I am going to re-implement my error handling and see if it gives us more clarity with impl.

              • estebank 10 hours ago ago

                You might want to look at anyhow and thiserror, the former for applications and for libraries the latter. thiserror "just" makes it easier to do what I suggested of writing a manual `impl From` so that `?` can transform from the error you're getting to the error you want. When the API you consume is very granular, that's actually great because it means that you have a lot of control over the transformation (it's hard to add detail that isn't already there), but it can be annoying when you don't care about that granularity (like when you just want to emit an error during shutdown or log during recovery).

                https://momori.dev/posts/rust-error-handling-thiserror-anyho...

                burntsushi has a good writeup about their difference in usecase here:

                https://www.reddit.com/r/rust/comments/1cnhy7d/whats_the_wis...

    • nicoburns 2 days ago ago

      100% I came to Rust from a primarily JavaScript/TypeScript background, and most of the idioms and approaches I was used to using translated directly into Rust.

      • christophilus 2 days ago ago

        Including pulling in hundreds of dependencies, unfortunately.

    • aiono a day ago ago

      A lot of criticism of Rust (not denying that there are also a lot useful criticisms of Rust out there) boils down to "it requires me to think/train in a different way than I used to, therefore it's hard" and goes on to how the other way is easier which is not the case but it's just familiar to them hence they think it's easier and simpler. More people should watch the talk "Simple made easy" https://www.youtube.com/watch?v=SxdOUGdseq4

    • tleyden5iwx 2 days ago ago

      I don't think like a C programmer, my problem is that I think like a Java/Python/Go programmer, and I'm spoiled by getting used to having a garbage collector always running behind me cleaning up my memory poops.

      Even though Rust can end up with some ugly/crazy code, I love it overall because I can feel pretty safe that I'm not going to create hard-to-find memory errors.

      Sure, I can (and do) write code that causes my (rust) app to crash, but so far they've all been super trivial errors to debug and fix.

      I haven't tried Zig yet though. Does it give me all the same compile time memory usage guarantees?

      • seemaze 2 days ago ago

        At first, the 12 year old inside me giggled at the thought of 'memory poops', but then I realized that a garbage collector is much more analogous to a waste water treatment plant than a garbage truck and a landfill..

    • amelius 2 days ago ago

      > Seasoned Rust coders don’t spend time fighting the borrow checker

      Yes, they know when to give up.

      • Ygg2 a day ago ago

        Nah. Just learn to think like it.

    • ajross a day ago ago

      > Seasoned Rust coders don’t spend time fighting the borrow checker - their code is already written in a way that just works.

      That hasn't been my experience at all. At best, the first version of code pops out quickly and cleanly because the author knows the appropriate idiom to choose. Refactoring rust code to handle changes in that allocation idiom is extremely expensive, even for the most seasoned developers.

      Case in point:

      > Once you’ve been using Rust for a while, you don’t have to “restructure” your code to please the borrow checker, because you’ve already thought about “oh, these two variables need to be mutated concurrently, so I’ll store them separately”.

      Which fails to handle "these two variables didn't need to be mutated concurrently, but now they do".

      • simonask a day ago ago

        This is an interesting comment, because you point directly at the exact reason Rust’s approach is so productive.

        In the C/C++/Zig code, you would add the second concurrent access, and then start fixing things up and restructuring things - if you, the programmer, knew about the first access, and knew that the concurrent access is a problem.

        In countless cases, that work would not be done, and I cannot blame any of the involved people, because managing that kind of detailed complexity over the lifespan of a project is not humanly possible. The result is another concurrency bug, meaning UB in production.

        Having the compiler tell you about such problems up front, exactly when they happen, is a complete game changer.

        • ajross a day ago ago

          > In the C/C++/Zig code, you would add the second concurrent access, and then start fixing things up and restructuring things

          Well, sure, which in practice means throwing a lock around it.

          I mean, I get it. There's a category of bugs that happen in real code. Rust chooses some categories of bugs (certainly not all of them) to construct walls around and forces code into idioms that can be provably correct for at least a subset[1] of the bug space. For the case of memory safety, that's a really pretty convincing case. Other areas are less clear; in particular I'm not a fan of Rust's idea of threadsafety and don't think it fits what actually performance-parallel code needs.

          [1] You can 100% write racy code with Sync/Send! You can write racy code with boring filesystem access using 100% safe rust (or 1980's csh code, whatever), too. Race conditions are inherent to concurrency. Sync/Send just protect memory access, they do nothing to address semantic/state bugs.

          • simonask 20 hours ago ago

            This is true out of the box - Rust isn't magical, and it can't fix all your bugs for you. But it does make its own tools available to you, an API designer. Lifetimes are available to you without ever making any actual references, and the Send/Sync traits are available to you without constructing any standard synchronization mechanism.

            You can construct something like `PhantomData<&mut ()>` to express invariants like "while this type exists, these other operations are unavailable". You can implement Send and/or Sync to say things like "under these specific conditions, this thing is thread safe". These are really powerful features of the type system, and no other mainstream language can really express such invariants at compile time.

            • ajross 17 hours ago ago

              Again though, I don't see a lot of value there. You seem to be implicitly repeating the prior that rust prevents race conditions, and it emphatically does not. It detects and prevents concurrent unlocked[1] access to a single memory location, which is not the same thing. Real races are much more complicated than that and happen in the semantic space of the application, not the memory details (again, think of email lockfiles as a classic race that has nothing to do with memory at all).

              [1] Though with overhead. It's tends not to be possible in safe rust to get it to generate code that looks like a pthread_mutex critical section. This again is one of my peeves, you do dangerous shared memory concurrency for performance!

      • mattwilsonn888 a day ago ago

        I would be interested to read the debates that stems from this point.

    • bsder a day ago ago

      > Seasoned Rust coders don’t spend time fighting the borrow checker - their code is already written in a way that just works.

      I really wish people would quit bleating on about the borrow checker. As someone who does systems programming, that's not the problem with Rust.

      Which Trait do I need to do X? Where is Trait Y and who has my destructor? How am I supposed to refactor this closure into a function? Sigh, I have to wrap yet another object as a newtype because of the Orphan Rule. Ah yes, an eight deep chain initialization calls because Rust won't do named/optional function arguments. Oh, great, the bug is inside a macro--well, there goes at least one full day. Ah, an entity component systems that treats indices like pointers but without the help of the compiler so I can index into the void and scribble over everything--but, hey, it's memory safe and won't segfault (erm, there is a reason why C programmers groan when they get a stack/heap smasher bug).

    • seivan 2 days ago ago

      [dead]

  • K0nserv a day ago ago

    I mostly don't agree with this take. A couple of my quibbles:

    "Cognitive overhead: You’re constantly thinking about lifetimes, ownership, and borrow scopes, even for simple tasks. A small CLI like my notes tool suddenly feels like juggling hot potatoes."

    None of this goes away if you are using C or Zig, you just get less help from the compiler.

    "Developers are not idiots"

    Even intelligent people will make mistakes because they are tired or distracted. Not being an idiot is recognising your own fallibility and trying to guard against it.

    What I will say, that the post fails to touch on, is: The Rust compiler's ability to reason about the subset of programs that are safe is currently not good enough, it too often rejects perfectly good programs. A good example of this it the inability to express that the following is actually fine:

        struct Foo {
            bar: String,
            baz: String,
        }
    
        impl Foo {
            fn barify(&mut self) -> &mut String { 
                self.bar.push_str("!");
                &mut self.bar
            }
            
            fn bazify(&self) -> &str {
                &self.baz
            }
        }
    
        fn main() {
            let mut foo = Foo {
                bar: "hello".to_owned(),
                baz: "wordl".to_owned(),
            };
            let s = foo.barify();
            let a = foo.bazify();
            s.push_str("!!");
        }
    
    which leads to awkward constructs like

        fn barify(bar: &mut String) -> &mut String { 
            bar.push_str("!");
            bar
        }
    
        // in main
        let s = barify(&mut foo.bar);
    • mattwilsonn888 a day ago ago

      To contradict you: avoiding false positives (programmer is correct, compilation fails anyways) by refactoring code into the second or third best design, is exactly the type of cognitive overhead that deserves to be vindicated when complained about. It can fundamentally changes the design of the entire codebase.

      I believe that explains why many game developers, who have a very complex job to do by default, usually see the Rust tradeoff as not worth it. Less optionality in system design compounds the difficulty of an already difficult task.

      If The Rust Compiler never produced false positives it should in theory be (ignoring syntactic/semantic flaws) damn-near as ergonomic as anything. Much, much easier said than done.

      • K0nserv a day ago ago

        You aren't really contradicting me, I agree that Rust isn't a great language for prototyping. However, there are some solutions that help with prototyping, namely: judicious use of Clone‚ Arc, Rc, and unsafe.

        In particular, if your comparison point is C and Zig and you don't care about safety you could use unsafe, knowing you are likely triggering UB, and be in mostly the same position as you would in C or Zig.

        • mattwilsonn888 a day ago ago

          Let me be more clear: the cognitive overhead is real, and does go away with less constraining languages. If that doesn't disagree with your previous point then I misread it.

          And I was making a point even more general than prototyping, though I also wouldn't discount the importance of that either.

    • dayvster a day ago ago

      this is an excellent example do you mind if I examine it a bit closer and perhaps use it in my article?

      • K0nserv a day ago ago

        Yes of course, although, as I said in a sibling comment, it's a bit convoluted as an example. The fundamental problem is that the xor mutable and shared reference rule gets in your way when you access separate fields through &self and &mut self even if the borrows are non-overlapping.

        There has been discussion to solve this particular problem[0].

        0: https://github.com/rust-lang/rfcs/issues/1215

        • minraws a day ago ago

          That RFC and Polonius, which Rust folks have been working on for the last 5-6 years is proof that there has been much effort made in related directions.

          Rust being sub par for so long just shows how much people won't want to fund these problems and how hard they are to solve during program compile.

          I ofc like Zig quite a bit but I find Rust to suit my tastes better. Zig feels too much like C with extra steps. And the lack of good tooling and stability around Zig hurts large scale adoption.

          But I think in 10 years Zig will be the de facto better-ish C.

          And Rust will be the low level language for any large project where safety is amongst the top 3 priorities.

          • K0nserv a day ago ago

            The problems Rust are trying to solve are both novel and difficult so it isn't particularly surprising that it's taking time. The team has also landed great improvements, like NLL. I'm optimistic about the direction of this, even if it takes time.

            Zig feels much younger than Rust so we'll see how it develops, but it's certainly interesting. In particular, comptime and explicit allocators are two ideas I hope Rust borrow more from Zig.

            > And Rust will be the low level language for any large project where safety is amongst the top 3 priorities.

            Personally I don't really see what'd be left for Zig, because in most software of consequence safety is already a top 3 priority.

    • Svoka a day ago ago

      Looking at your code I have more confidence that quoted statement is false.

      • K0nserv a day ago ago

        Which statement and why? The code is obviously stupid and convoluted because I threw it together in a minute to illustrate a point.

    • a day ago ago
      [deleted]
  • scoopdewoop 2 days ago ago

    This is a really bad take, on par with the "we don't need types" post from last week.

    The thing I wish we would remember, as developers, is that not all programs need to be so "safe". They really, truly don't. We all grew up loving lots of unsafe software. Star Fox 64, MS Paint, FruityLoops... the sad truth is that developers are so job-pilled and have pager-trauma, so they don't even remember why they got in the game.

    I remember reading somewhere that Andrew Kelley wrote zig because he didn't have a good language to write a DAW in, and I think its so well suited to stuff like that! Make cool creative software you like in zig, and people that get hella about memory bugs can stay mad.

    Meanwhile, everyone knows that memory bugs made super mario world better, not worse.

    • AlotOfReading a day ago ago

          The thing I wish we would remember, as developers, is that not all programs need to be so "safe".
      
      "Safety" is just a shorthand for "my program means what I say". Unsafety is semantic gibberish.

      There's lots of reasons to write artistically gibberish code, just as there is with natural language (e.g. Lewis Carroll). Most programs aren't going for code as art though. They're trying to accomplish something definite through a computer and gibberish is directly counterproductive. If you don't mean what you write or care what you get, software seems like the wrong way to accomplish your goals. I'd still question whether you want software even in a probabilistic argument along these lines.

      Even for those cases where gibberish is meaningful at a higher level (like IOCCC and poetry), it should be intentional and very carefully crafted. You can use escape hatches to accomplish this in Rust, though I make no comment on the artistic merits of doing so.

      The argument you're making is that uncontrolled, unintentional gibberish is a positive attribute. I find that a difficult argument to accept. If we could wave a magic wand and make all code safe with no downsides, who among us wouldn't?

      It doesn't change anything about Super Mario World speedruns because you can accomplish the same thing as arbitrary code execution inputs with binary patching. We just have this semi-irrational belief that one is cheating and one is not.

      • discreteevent a day ago ago

        You are not doing Rust any favours by arguing that code that may have memory safety issues is gibberish and something that could be associated with the IOCCC. Ramping something up to 11 makes it hard to take seriously.

        You could write rust code with logic errors. I could write C with a memory leak that doesn't matter because of the context it runs in. Neither program is gibberish but one of them causes real problems.

        • AlotOfReading a day ago ago

          I'm not making either of those arguments. I'm not even using IOCCC as a pejorative association. The comment you're responding to explicitly compares IOCCC code to poetry and Lewis Carroll. One thing I am saying is that most code isn't written for those kinds of purposes. I can't imagine that's a controversial statement though.

          I'm open to suggestions on how to clarify things as you're the second comment to misunderstand it and I'm not sure how to better explain it.

      • clevor a day ago ago

        If you want or need the guarantees Rust provides, then go ahead and use Rust. If you want to handle the guarantees yourself, then Rust may not be the language for you. You can still have bugs whether or not you use Rust, so your Rust program may have some form of unsafety. In Linux, a Rust program with setuid root can lead to privilege escalation vulnerabilities, even if it doesn't contain a single line of "unsafe" code.

        Either way, telling someone they have to pick between using a safe language like Rust and writing "semantically gibberish" is a false dichotomy. Please don't call programs written in memory-unsafe languages semantic gibberish until you prove that there are absolutely zero bugs in your program.

        • simonask a day ago ago

          I think you have both misread the comment you replied to and misunderstood the concept of memory safety.

      • scoopdewoop a day ago ago

        > If we could wave a magic wand and make all code safe with no downsides, who among us wouldn't?

        Anybody would, but Rust is not that wand, and there is no wand.

        Code needs to _exist_ in order to matter. Time is finite, my free-time is even more limited. Most of my code is garbage collected, and runs great, but if I needed it to be really fast, I would use Zig.

        I don't need to be told what software is for or how to accomplish my goals, and I'm sure you wouldn't understand my goals. I've been making code creatively for almost 30 years. You might as well tell an origami artist that folding paper is a bad way to accomplish their goals.

        The attitude among _some_ Rust devs (or armchair coders) that there is no place for non-rust manual-memory languages is insanely disconnected with reality. Games exist, Rust ones hardly do. Synths exist, Rust ones hardly do. Not everything is a high-availability microservice or an OS kernel! Look around!

        Edited to add:

        > "Safety" is just a shorthand for "my program means what I say". Unsafety is semantic gibberish.

        You know this isn't true, right? "Safety" in Rust specifically means memory safety and thread safety: no use-after-free, no data races, no null/dangling pointer dereferences, no buffer overflows. That's it. It doesn't guarantee your program is correct, and it doesn't even prevent memory leaks.

        Things being manually managed doesn't make them gibberish, and something being implicit, rather than explicit, doesn't mean its gibberish.

        The attitude of Rust being bug-free is _insaaaane_. A "bug" is just code that breaks expectations, I promise we can and will write those in every language forever.

        • vrmiguel 9 hours ago ago

          > The attitude of Rust being bug-free is _insaaaane_.

          Funny, because that's not anywhere close to what the comment you're replying to states.

          They said `"Safety" is just a shorthand for "my program means what I say"`. That's a reasonable explanation: the code you wrote is not working exactly as you intended, due to some sort of unknown behavior.

          The "bug" you're talking about would be the program doing exactly what you implemented, but what you implemented is wrong. The difference is so obvious that it's hard to think that you're engaging in a good faith argument.

        • AlotOfReading a day ago ago

          I want to be clear here because I think you might have read that as less precisely worded than I intended.

          When I say "my program means what I say", that means the code that is written has some precise meaning that can be faithfully translated into execution (sans hardware/runtime/toolchain bugs).

          This is different than "I said what I mean". If you write different code, that may violate expectations and create a bug, but it will still be faithfully translated as written.

          Safe Rust attempts to guarantee this with the absence of UB. The definition rust uses still isn't a universal definition, which we agree on. That's why my comment didn't actually talk about Rust. The definition I used should be valid no matter what particular guarantees you choose.

              Things being manually managed doesn't make them gibberish, and something being implicit, rather than explicit, doesn't mean its gibberish.
          
          I completely agree. I like C, for what it's worth.

          Where we disagree is that I'm saying this doesn't scale. A large enough program (for a surprisingly small definition of large) will always have gaps and mistakes that violate your chosen definition of safety, and those bits are the gibberish I'm talking about.

          • scoopdewoop a day ago ago

            I understood and considered both things you could have meant. Either way I think you come off as an armchair coder that overstates what rust safety actually is (its not abstract, i enumerated it). You are doing rust a disservice in the most stereotypical way. I have no more time for this, going to go play one of hundred of thousands of gibberish games.

    • dayvster 2 days ago ago

      Uh I'm confused, so you think my take is bad because memory safety should not matter ?

      • scoopdewoop 2 days ago ago

        I think its a bad take because "Developers are not Idiots" and "be disciplined" are not good arguments. Its just choosing to ignore the problem rust solves.

        I am fine with ignoring the problems that rust solves, but not because I'm smart and disciplined. It just fits my use-case of making fast _non-critical_ software. I don't think we should rewrite security and networking stacks in it.

        • dayvster 2 days ago ago

          Then we're sort of in agreement.

          I don't think you need the ritual and complexity that rust brings for small and simple scripts and CLI utilities...

          • KuSpa a day ago ago

            And rust doesn't market itself as small and simple scripting language?

            Choose the tool that fits your usecase. You would never bring wasm unity to render a static html file. But if you make a browsergame, you might want to.

  • karmakaze 2 days ago ago

    I was going to say that it's greatly understating the value of the borrow checker. It guarantees no invalid memory accesses. But then it added:

    > This means that basically the borrow checker can only catch issues at comptime but it will not fix the underlying issue that is developers misunderstanding memory lifetimes or overcomplicated ownership. The compiler can only enforce the rules you’re trying to follow; it can’t teach you good patterns, and it won’t save you from bad design choices.

    In the short times that I wrote Rust, it never occurred to me that my lifetime annotations were incorrect. They felt like a bit of a chore but I thought said what I meant. I'm sure there's a lot of getting used to using it--like static types--and becomes second nature at some point. Regardless, code that doesn't use unsafe can't have two threads concurrently writing the same memory.

    The full title is "Why Zig Feels More Practical Than Rust for Real-World CLI Tools". I don't see why CLI tools are special in any respect. The article does make some good points, but it doesn't invalidate the strength of Rust in preventing CVEs IMO. Rust or Zig may feel certain ways to use for certain people, time and data will tell.

    Personally, there isn't much I do that needs the full speed of C/C++, Zig, Rust so there's plenty of GC languages. And when I do contribute to other projects, I don't get to choose the language and would be happy to use Rust, Zig, or C/C++.

    • kllrnohj 2 days ago ago

      > I don't see why CLI tools are special in any respect.

      Because they don't grow large or need a multi-person team. CLI tools tend to be one & done. In other words, it's saying "Zig, like C, doesn't scale well. Use something else for larger, longer lived codebases."

      This really comes across in the article's push that Zig treats you like an adult while Rust is a babysitter. This is not unlike the sentiment for Java back in the day. But the reality is that most codebases don't need to be clever and they do need a babysitter.

      • vlowther a day ago ago

        It isn't even really that -- most CLI tools are single-threaded and have a short lifespan, so your memory allocation strategy can be as simple as allocating what you need as you go along and then letting program termination clean it up.

      • johncolanduoni 2 days ago ago

        I think this focus cuts both ways though - most "one & done" CLI tools will not be bottlenecked by a GC. Many are so performance insensitive that Python is totally fine, and for most of the rest the performance envelope of Go is more than enough. Why would I reach for Rust or Zig for these? "I like C, Zig is like C" is a totally acceptable reason, but then this whole article is preaching to the choir.

        • karmakaze a day ago ago

          I was with you on using safe languages Go/Python. I disagree that using Zig == using Rust. Many CLI programs get run as root (sudo or otherwise) either necessarily or out of laziness/convenience.

      • Klonoar a day ago ago

        Rust isn’t a babysitter so much as it is having a second adult in the room that you’re bouncing stuff off of; they just care about memory safety and will tell you when you’re doing something stupid. You can override them if you want to.

      • cestith 2 days ago ago

        Do you know any other languages that tend to be safer than C and suitable for CLI tools but without the borrow checker? Over many years I’ve seen a lot in C++, Go, Perl, Python, Ruby, Pascal, various shells, assembly, Java, and some in Haxe, Ada, Lisp, Scheme, Julia, forms of Basic, and recently JavaScript or Typescript.

        Most of those are more memory safe than C. None of them have the borrow checker. This leaves me wondering why - other than proselytizing Zig - this article would make such a direct and narrow comparison between only Zig and Rust.

        • pjmlp a day ago ago

          OCaml for example,

          Unix system programming in OCaml, from 1991

          https://ocaml.github.io/ocamlunix/

          • cestith a day ago ago

            It’s such a nice language, too. It’s too bad it doesn’t get more attention. I know someone who regularly runs a couple of utilities written in Haskell, but they’re the only Haskell code in his entire organization. It’s a shop that has C, C++, Rust, JavaScript, TypeScript, Python, and Go in production, Java in legacy production, and has half a dozen other languages in production support situations. Haskell has not caught on there, though.

            I’m aware a few companies use primarily OCaml just as a few use primarily some form of Lisp. It’s just that some of these really nice languages don’t see as much use as they could.

        • tayo42 2 days ago ago

          With how easily go creates statically compiled binaries and cross compiles I think that might be best language for cli tools. Unfortunate becasue it's annoyingly unexpressive.

          • reddit_clone a day ago ago

            Indeed, but it is considered a strength by Go enthusiasts. Not being able to build clever abstractions is a feature.

            So is the error handling boilerplate.

    • hansvm a day ago ago

      > Regardless, code that doesn't use unsafe can't have two threads concurrently writing the same memory.

      It's a bit messier than that. Basically the only concurrency-related bug I ever actually want help with from the compiler is memory ordering issues. Rust chose to make those particular racey memory writes safe instead of unsafe.

      • a day ago ago
        [deleted]
  • Animats a day ago ago

    He has a point. Backlinks in Rust are too hard. You can do them safely with Rc, Weak, and RefCell, and .borrow(), but it's not trivial.

    If your program runs for a short time and then exits, arena editing is an option. That seems to be what the author means by "CLI tools". It's the lifetime, not the input format.

    "Rust is amazing, if you’re building something massive, multithreaded, or long-lived, where compile-time guarantees actually save your life. The borrow checker, lifetimes, and ownership rules are a boon in large systems."

    Yes. That's really what Rust is for. I've written a large metaverse client in Rust, and one of the regression tests I run is to put an avatar in a tour vehicle and let it ride around for 24 hours. About 20 threads. No memory leaks. No crashes. That would take a whole QA team and lots of external tools such as Valgrind in C++, and it would be way too slow in any of the interpreted languages.

    • hadlock a day ago ago

      I wrote a physics-accurate flight sim in rust that takes in to account the curvature of the earth and local gravitational fluctuations, it has two tests, one is to fly SFO-Sacramento-Seattle about a 5 hour "flight" at 60 frames per second, the longer one is to fly SFO to Tokyo about 22 hours; it has never once crashed or had a memory leak, it has always worked flawlessly. In 7 years of writing rust I've only ever had a handful of crashes, mostly when writing my own 2d software renderers. The only time I touch C or C++ these days is fixing legacy stuff.

      • 12_throw_away a day ago ago

        > I wrote a physics-accurate flight sim in rust

        Off-topic - that sounds amazing, is this commercial or hobby software? Any way I could learn more about it?

        • atonse 8 hours ago ago

          Yeah seriously, I was also intrigued by it!

  • giancarlostoro 2 days ago ago

    I want to like Zig, but D still exists and feels like everything I want from a C-like alternative to C++ I just wish the rest of the industry had adopted it long ago. Zig has a strange syntax, and Rust is basically eating chunks of the industry, especially in programmer tooling across various languages as is Go (it powers most cloud providers and is the 2nd top choice for AI right after Python).

    • sethops1 2 days ago ago

      I remember before Rust when Go vs. D was the topic of the day. I even bought a D book and was working through it when Go was announced, and it won me over. The difference maker for me was the standard library; working with Go was just easier, full stop. That and using names like 'int64' instead of 'double', because that's what my brain likes apparently.

      • giancarlostoro 2 days ago ago

        100% agree. I really love D the language, if I could go back in time I would find Walter and challenge him that he couldn't write {insert half of the Go std lib packages} into the STD lib for D because its too hard and impossible, in the hopes he takes the bait. I would love to see something like a 'Framework' for D that is maintained by the maintainers, but isn't necessarily the standard library, because people get really touchy when you mess with the STD lib, maybe a way to test the waters before actually adding new packages to it, having an HTTP server OOTB with D would be amazing.

    • pjmlp a day ago ago

      D would be great, unfortunately they never got the killer application for mass adoption.

  • nmilo a day ago ago

    I don't know why anyone would write CLI tools in rust or zig. I/O is going to be your bottleneck way more often than GC, in fact I don't really get the GC hate outside of game dev, databases and other memory intensive applications. Why not use Go, Python, etc? People try to make a false dichotomy between memory safety vs. non-memory safety when really it's GC vs. no GC --- memory safety without it is going to be hard either way. More time should be spent on justifying to yourself why you shouldn't be using a GC, and less on which kind of GC-less language you use.

    (If you go no GC "because it's fun" then there's no need for the post in the first place --- just use what's fun!)

    • shmolyneaux a day ago ago

      Instant startup times are really nice. You definitely notice the difference. It also means that you can be a bit lazier when creating wrappers around those tools (running 1000's of times isn't a problem when the startup is 1ms, but would be a problem with 40ms of startup time).

      Distribution can also be a lot easier if you don't need to care about the user having a specific version of Python or specific packages available.

      • rixed a day ago ago

        What makes python very slow start up has little to do with the GC though. Actually, a GC program for a short-lived program such as most CLI tools can be the fastest option since you could disable the GC and let the OS dealloc all memory at exit.

      • nmilo a day ago ago

        Fair. Python was probably a bad example. I think we need more languages like Go because even with its downsides, for projects that don’t need explicit memory control I’m picking it over rust and zig every time

    • seabrookmx a day ago ago

      Go is a great option for CLI tools (even though I'm not a fan of the language itself). Python CLI apps can be a big pain to distribute if you have a bunch of dependencies. I think this is also why Rust and Zig are also attractive.. like with Go it's easy to create a statically compiled binary you can just cp into /usr/local/bin.

    • efnx a day ago ago

      I will always reach for a language that has sum types, pattern matching and async support. Catching errors at compile time is a boon too. It doesn’t have to be Rust, but after those requirements- why not?

    • astrange a day ago ago

      > in fact I don't really get the GC hate outside of game dev

      Most mobile games are implemented in a system with GC (Unity with il2cpp), and it's not even a /good/ GC, it's Boehm.

    • pjmlp 20 hours ago ago

      It is basically cargo cult, whole graphical workstations have been built with GC based languages 50 years ago.

      - Interlisp => https://interlisp.org/

      - Cedar => https://www.youtube.com/watch?v=z_dt7NG38V4

      Imagine what we could have today with hardware that is mostly busy running Electron crap and CLI tools from the 1970s.

    • K0nserv a day ago ago

      Not Python because getting Python to run on different machines is an absolute pain.

      Not Go because of its anaemic type system.

  • articulatepang a day ago ago

    > Last weekend I’ve made a simple CLI tool for myself to help me manage my notes it parses ~/.notes into a list of notes, then builds a tag index mapping strings to references into that list. Straightforward, right? Not in Rust. The borrow checker blocks you the moment you try to add a new note while also holding references to the existing ones. Mutability and borrowing collide, lifetimes show up, and suddenly you’re restructuring your code around the compiler instead of the actual problem.

    I'd love to see the actual code here! When I imagine the Rust code for this, I don't really foresee complicated borrow-checker or reference issues. I imagine something like

      struct Note {
        filename: String,
        // maybe: contents: String
      }
    
      // newtype for indices into `notes`
      struct NoteIdx(usize);
    
      struct Notes {
        notes: Vec<Note>,
        tag_refs: HashMap<String, Vec<NoteIdx>>
      }
    
    You store indices instead of pointers. This is very unlikely to be slower: both a usize index and a pointer are most likely 64 bits on your hardware; there's arguably one extra memory deref but because `notes` will probably be in cache I'd argue it's very unlikely you'll see a real-life performance difference.

    It's not magic: you can still mess up the indices as you add and remove notes.

    But it's safer: if you mess up the indices, you'll get an out-of-bounds error instead of writing to an unintended location in your process's memory.

    Anyway, even if you don't care about safety, it's clear and easy to think about and reason about, and arguably easier to do printf debugging with: "this tag is mentioned in notes 3, 10 and 190, oh, let's print out what those ones are". That's better than reading raw pointers.

    Maybe I'm missing something? This sort of task comes up all day every while writing Rust code. It's just a pretty normal pattern in the language. You don't store raw references for ordinary logic like this. You do need it when writing allocators, async runtimes, etc. Famously, async needs self-referential structs to store stack local state between calls to `.await`, and that's why the whole business with `Pin` exists.

    • erk__ a day ago ago

      Pointers to a vec could also be invalidated at any point when adding a new element and causing a reallocation

      (I think Miri will shout at you if you use a invalidated pointer here)

  • HackerThemAll a day ago ago

    > whereas Zig has good developer ergonomics and allows me to produce memory safe software with a bit of discipline

    C also allows to produce memory safe software with a bit of discipline. This "bit of discipline" is the issue here which developers are lacking.

    • davemp 17 hours ago ago

      There are levels here, Zig addresses:

      - out of bounds access (70% of CVEs)

      - nullptr dereferences

      - type safety issues

      That’s massively better than C. Preventing use after free errors requires much less discipline than never missing a boundary or bungling a signed/unsigned conversion.

      Zig also has a knock your socks off incredible cross platform build system, empowers some really nice optimizations/ergonomics with comptime, has orders of magnitude faster build times that C++/rust.

      Zig is still < v1.0 so standard library could use some work and there are other warts, but I think it will be a great choice for performance oriented programs in the future.

    • pjmlp 20 hours ago ago

      It must be harder than Shaolin discipline, given the failure after 50 years.

  • antoineMoPa 2 days ago ago

    I also loved Zig when manually typing code, but I increasingly use AI to write my code even in personal projects. In that context, I'd rather use Rust more, since the AI takes care of complex syntax anyway. Also, the rust ecosystem is bigger, so I'd rather stick to this community.

    > Developers are not Idiots

    I'm often distracted and AIs are idiots, so a stricter language can keep both me and AIs from doing extra dumb stuff.

    • kevinrineer a day ago ago

      > I'm often distracted

      I really appreciate this in my role, where I have an office right next to the entrance to the building. I get walk-ins all of the time. When my door is closed, I get knocks on the door all of the time. Both AI and strict languages are great tools in my environment, where focus for me is as abundant as water in a desert.

  • travisgriggs a day ago ago

    > memory safety is one puzzle piece of overall software safety

    So this. We currently spent about a month carefully instrumenting and coming to understand a subtle bug in our distributed radio network. This all runs on bare metal C (samd21 chips). Because timing, and hundreds of little processors, and radios were all involved, it was a pita to surface what the issue was. It was algorithmic. Not a memory problem. Writing this in rust or zig (instead of straight C) would not have fixed this problem.

    I’d like to consider doing next generations of this product in zig or rust. I’m not opposed. I like the extra tools to make the product better. But they’re a small part of the picture in writing good software. The borrow checker may improve your code, it doesn’t guarantee successful software.

  • efnx a day ago ago

    > You’re constantly thinking about lifetimes, ownership, and borrow scopes, even for simple tasks.

    As a professional Rust developer, I don’t find I do this. I occasionally think of those things. But I do remember a short adjustment period when I was learning Rust that I would get frustrated by the borrow checker. Of course, that’s it doing its job!

  • Someone a day ago ago

    “Rust lifetimes can be chore, so use a C-like language that requires you to manage them in your head”

    Weird that they don’t consider other options, in particular languages with reference counting or garbage collection. Those will not solve all ownership issues, but for immutable objects, they typically do. For short-running CLI tools, garbage collecting languages may even be faster than ones with manual memory management because they may be able to postpone all memory freeing until the program exits.

  • swiftcoder 2 days ago ago

    This article seems pretty confused about what the borrow checker does or does not do - I've never heard compile time enforcement listed as a negative of the borrow checker before. It might do the author good to try writing some (non-trivial) memory management in both Zig and Rust some time.

  • YmiYugy 15 hours ago ago

    Zig is pretty neat. Compiles quickly, integrates nicely with C and its sdtlib was designed with explicit allocators in mind. It's a perfectly fine choice for building small CLIs, but many of the criticisms of rust just don't land right of me. Let's go through some slightly exaggerated interpretations of them. 1. Relying on the compiler for memory management makes you a bad programmer: Every skill has its applications, but having a compiler that ensures memory safely (for the most part) changes what is required of a good programmer and being able to safely manage memory by hand is less important. 2. The borrow checker is all or nothing: If you use unsafe or turn your memory bugs into logic bugs by using indexes you do miss out on safety guarantees of the borrow checker, but a) Rust has other compelling features, e.g. pattern matching, parametricity, b) Zig/C safety doesn't hold up better when doing things that require unsafe in Rust, c) the unsafe use and index wrangling can be encapsulated. The rest of your code can use the borrow checker just fine. 3. But safety is more than memory safety: Of course there is. I think this is a bit of a straw man argument, because I don't think that's a common claim the rust community let alone the foundation makes. 4. Rust strongly encourages you to structure your code around the compiler: I think this claim is valid, but I want to dispute that this is such a bad thing. You are probably a log smarter than the compiler. So you need to dumb it down, so the compiler will understand. Code that requires less brain power to understand is usually good. I've had some experiences where the borrow checker guided me to find a nicer structure for my code. The learning curve however is real. It takes a lot of time to build the intuition around the borrow checker and not run head first into it all the time. IMHO for small CLI tools it's fine to clone your way out of a dead end, even if it seems ugly.

  • GardenLetter27 a day ago ago

    Nope, rust-analyzer is incredible whereas the Zig LSP felt worse than Go.

    I agree the borrow checker can be a pain though, I wish there were something like Rust with a great GC. Go has loads of other bad design decisions (err != nil, etc.) and Cargo is fantastic.

    • seabrookmx a day ago ago

      Syntactically speaking, Gleam fits the bill. It's very new/immature though and isn't in the same performance bracket since it runs on the BEAM.

      • mackeye a day ago ago

        how is its startup time? ive wanted to learn it or ocaml for a while and might take the plunge

        • seabrookmx a day ago ago

          I only wrote some toy programs in it, and it didn't jump out to me as an issue. I don't have any real data for you though, sorry!

  • bfrog 2 days ago ago

    Because it doesn't actually enforce anything and lets you blow your foot off just like C?

  • KingOfCoders 2 days ago ago

    "All it took was some basic understanding of memory management and a bit of discipline."

    The words of every C programmer who created a CVE.

    • pron a day ago ago

      What about every Java/JS/Python/Rust/Go programmer who ever created a CVE? Out-of-bounds access is, indeed, a very common cause of dangerous vulnerabilities, but Zig eliminates it to the same extent as Rust. UAF is much lower on the list, to the point that non-memory-safety-related causes easily dominate it.[1]

      The question is, then, what price in language complexity are you willing to pay to completely avoid the 8th most dangerous cause of vulnerabilities as opposed to reducing them but not eliminating them? Zig makes it easier to find UAF than in C, and not only that, but the danger of UAF exploitability can be reduced even further in the general case rather easily (https://www.cl.cam.ac.uk/~tmj32/papers/docs/ainsworth20-sp.p...). So it is certainly true that memory unsafety is a cause of dangerous vulnerabilities, but it is the spatial unsafety that's the dominant factor here, and Zig eliminates that. So if you believe (rightly, IMO) that a language should make sure to reduce common causes of dangerous vulnerabilities (as long as the price is right), then Zig does exactly that!

      I don't think it's unreasonable to find the cost of Rust justified to eliminate the 8th most dangerous cause of vulnerabilities, but I think it's also not unreasonable to prefer not to pay it.

      [1]: https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html

      • johncolanduoni a day ago ago

        I don't think the rank on a list that includes stuff like SQL injection and path traversal tells you much about what language features are worthwhile in the C/C++ replacement space. No developer that works on something like Linux or Chromium would introduce a SQL injection vulnerability unless they experienced severe head trauma. They do still introduce use after free vulnerabilities with some regularity.

        • pron a day ago ago

          First, UAF can be made largely non-dangerous without eliminating it (as in the link above and others). It's harder to exploit to begin with, and can be made much harder still virtually for free. So the number of UAFs and the number of exploitable vulnerabilities due to UAF are not the same, and have to be treated as separate things (because they can be handled separately).

          Second, I don't care if my bank card details leak because of CSRF or because of a bug in Chromium. Now, to be fair, the list of dangerous vulnerabilities weighs things by number of incidents and not by number of users affected, and it is certainly true that more people use Chrome than those who use a particular website vulnerable to CSRF. But things aren't so simple, there, too. For example, I work on the JVM, which is largely written in C++, and I can guarantee that many more people are affected by non-memory-safety vulnerabilities in Java programs than by memory-safety vulnerabilities in the JVM.

          Anyway, the point is that the overall danger and incidence of vulnerabilities - and therefore the justified cost in addressing all the different factors involved - is much more complicated than "memory unsafety bad". Yes, it's bad, but different kinds of memory unsafety are bad to different degrees, and the harm can be controlled separately from the cause.

          Now, I think it's obvious that even Rust fans understand there's a complex cost/benefit game here, because most software today is already written in memory-safe languages, and the very reason someone would want to use a language like Rust in the first place is because they recognise that sometimes the cost of other memory-safe languages isn't worth it, despite the importance of memory safety. If both spatial and temporal safety were always justified at any reasonable cost (that is happily paid by most software already), then there would be no reason for Rust to exist. Once you recognise that, you have to also recognise that what Rust offers must be subject to the same cost/benefit analysis that is used to justify it in the first place. And it shouldn't be surprising that the outcome would be similar: sometimes the cost may be justified, sometimes it may not be.

          • johncolanduoni a day ago ago

            > I don't care if my bank card details leak because of CSRF or because of a bug in Chromium

            Sure, but just by virtue of what these languages are used for, almost all CSRF vulnerabilities are not in code written in C, C++, Rust, or Zig. So if I’m targeting that space, why would I care that some Django app or whatever has a CSRF when analyzing what vulnerabilities are important to prevent for my potential Zig project?

            You’re right that overall danger and incidence of vulnerabilities matter - but they matter for the actual use-case you want to use the language for. The Linux kernel for example has exploitable TOCTOU vulnerabilities at a much higher rate than most software - why would they care that TOCTOU vulnerabilities are rare in software overall when deciding what complexity to accept to reduce them?

            • pron a day ago ago

              To your first point, you're sort-of right, but it's still not so simple. The value of vulnerabilities in V8 or in CPython is affected by their likelihood compared to other vulnerabilities to users using that same product (i.e. in JS or Python code). If I want to know how much I should pay for a screw in some machine, the answer isn't "whatever it costs to minimise the chance of the screw failing regardless of other components". Once the chance of a fault in the screw is significantly lower than the chance of the machine failing for other reasons, there's no much point in getting a more resilient screw, as it would have little to no effect on the resilience of the machine.

              The rate of vulnerabilities obviously can't be zero, but it also doesn't need to be. It needs to be low enough for the existing coping processes to work well, and those processes need to be applied anyway. So really the question is always about cost: what's the cheapest way for me to get to a desired vulnerability rate?

              Which brings me to why I may prefer a low-level language that doesn't prevent UAF: because the language that does present UAF has a cost that is not worth it for me, either because UAF vulnerabilities are not a major risk for my application or because I have cheaper ways to prevent them (without necessarily eliminating the possibility of UAF itself), such as with one of the modern pointer-tagging techniques.

              • johncolanduoni a day ago ago

                I buy that Zig would fit the risk/reward envelope for some projects. My only issue was with using a breakdown of amalgamated CVEs where most of the software would never actually be written in Zig or Rust regardless to demonstrate that. Perhaps that misunderstanding about my claims is most of the source of our disagreement.

                To your point about V8 and CPython: that calculus makes sense if I’m Microsoft and I could spend time/money on memory safety in CPython or on making CSRF in whatever Python library I use harder. My understanding is that the proportions of the budget for different areas of vulnerability research at any tech giant would in fact vindicate this logic.

                However, if I’m on the V8 team or a CPython contributor and I’m trying to reduce vulnerabilities, I don’t have any levers to pull for CSRF or SQL injection without just instead working on a totally different project that happens to be built on the relevant language. If my day job is to reduce vulnerabilities in V8 itself, those would be totally out of scope and everybody would look at my like I’m crazy if I brought it up in a meeting.

                Similarly, if I’m choosing a language to (re)write my software in and Zig is on the table, I am probably not super worried about CSRF and SQL injection - most likely I’m not writing an API accessed by a browser or interfacing with a SQL database at all! Also I have faith that almost all developers who know what Zig is in the first place would not write code with a SQL injection vulnerability in any language. That those are still on the top ten list is a condemnation of our entire species, in my book.

                • pron a day ago ago

                  > If my day job is to reduce vulnerabilities in V8 itself, those would be totally out of scope and everybody would look at my like I’m crazy if I brought it up in a meeting.

                  Maybe (and I'll return to that later), but even if the job were to specifically reduce vulnerabilities in V8, it may not be the case that focusing on UAF is the best way to go, and even if it were, it doesn't mean that eliminating UAF altogether is the best way to reduce UAF vulnerabilities. More generally, memory safety => fewer vulnerabilities doesn't mean fewer vulnerabilities => memory safety.

                  When some problem is a huge cause of exploitable vulnerabilities and eliminating it is cheap - as in the case of spatial memory safety - it's pretty easy to argue that eliminating it is sensible. But when it's not as big a cause, when the exploits could be prevented in other ways, and when the cost of eliminating the problem at the source is high, it's not so clear cut that that's the best way to go.

                  The costs involved could actually increase vulnerabilities overall. A more complex language could have negative effects on correctness (and so on security) in some pretty obvious ways: longer build times could mean less testing; less obvious code could mean more difficult reviews.

                  But I would say that there's even a problem with your premise about "the job". The more common vulnerabilities are in JS, the less value there is in reducing them in V8, as the relative benefit to your users will be smaller. If JS vulnerabilities are relatively common, there could, perhaps, be more value to V8 users in improving V8's performance than in reducing its vulnerabilities.

                  BTW, this scenario isn't so hypothetical for me, as I work on the Java platform, and I very much prefer spending my time on trying to reduce injection vulnerabilities in Java than on chasing down memory-safety-related vulnerabilities in HotSpot (because there's more security value to our users in the former than in the latter).

                  I think Zig is interesting from a programming-language design point of view, but I also think it's interesting from a product design point of view in that it isn't so laser-focused on one thing. It offers spatial memory safety cheaply, which is good for security, but it also offers a much simpler language than C++ (while being just as expressive) and fast build times, which could improve productivity [1], as well as excellent cross-building. So it has something for everyone (well, at least people who may care about different things).

                  [1]: These could also have a positive effect on correctness, which I hinted at before, but I'm trying to be careful about making positive claims on that front because if there's anything I've learnt in the field of software correctness is that things are very complicated, and it's hard to know how to best achieve correctness. Even the biggest names in the field have made some big, wrong predictions.

                  • johncolanduoni a day ago ago

                    > BTW, this scenario isn't so hypothetical for me, as I work on the Java platform, and I very much prefer spending my time on trying to reduce injection vulnerabilities in Java than on chasing down memory-safety-related vulnerabilities in HotSpot (because there's more security value to our users in the former than in the latter).

                    That's a good example and I agree with you there. I think the difference with V8 though is twofold:

                    1. Nobody runs fully untrusted code on HotSpot today and expects it to stop anybody from doing anything. For browser JavaScript engines, of course the expectation is that the engine (and the browser built on it) are highly resistant to software sandbox escapes. A HotSpot RCE that requires a code construction nobody would actually write is usually unexploitable - if you can control the code the JVM runs, you already own the process. A JavaScript sandbox escape is in most cases a valuable part of an exploit chain for the browser.

                    2. Even with Google's leverage on the JS and web standardization processes, they have very limited ability to ship user-visible security features and get them adopted. Trusted Types, which could take a big chunk out of very common XSS vulnerabilities and wasn't really controversial, was implemented in Safari 5 years after Chrome shipped it. Firefox still doesn't support it. Let's be super optimistic and say that after another 5 years it'll be as common as CSP is today - that's ten years to provide a broad security benefit.

                    These are of course special aspects of V8's security environment, but having a mountain of memory safe code you can tweak on top of your unsafe code like the JVM has is also unusual. The main reason I'd be unlikely to reach for Zig + temporal pointer auth on something I work on is that I don't write a lot of programs that can't be done in a normie GC-based memory safe programming language, but for which having to debug UAF and data race bugs (even if they crash cleanly!) is a suitable tradeoff for the Rust -> Zig drop in language complexity.

                    • pron 13 hours ago ago

                      I agree with your observations about the differences between HotSpot and V8, but my general point is precisely that where you want to focus for security is complicated and application-specific, and that the relative risk of different vulnerability causes does matter.

                      As to your last point, I certainly accept that that could be the case for some, but the opposite is also likely: if UAF is not an outsized cause of problems, then a simpler language that, hopefully, can make catching/debugging all bugs easier could be more attractive than one that could be tilting too much in favour of eliminating UAF possibly at the expense of other problems. My point being that it seems like there are fine reasons to prefer a Rust-like approach over a Zig-like approach and vice-versa in different situations, but we simply don't yet know enough to tell which one - if any - is universally or even more commonly superior to the other.

      • pjmlp a day ago ago

        Ideally neither Zig nor Rust would matter.

        Languages like Modula-3 or Oberon would have taken over the world of systems programming.

        Unfortunately there are too many non-believers for systems programming languages with automatic resource management to take off as they should.

        Despite everything, kudos to Apple for pushing Swift no matter what, as it seems to be only way for adoption.

        • pron a day ago ago

          > Unfortunately there are too many non-believers for systems programming languages with automatic resource management to take off as they should.

          Or those languages had other (possibly unrelated) problems that made them less attractive.

          I think that in a high-economic-value, competitive activity such as software, it is tenuous to claim that something delivers a significant positive gain and at the same time that that gain is discarded for irrational reasons. I think at least one of these is likely to be false, i.e. either the gain wasn't so substantial or there were other, rational reasons to reject it.

          • johncolanduoni a day ago ago

            I’m not willing to go to bat for Oberon, but large swaths of software engineering are done with no tradeoff analysis of different technologies at all. Most engineers know one imperative programming language and maybe some SQL. If you ask them what to use, they will simply wax poetic about how the one language they know is the perfect fit for the use-case.

            Even for teams further toward the right of the bell curve, historical contingencies have a greater impact than they do in more grounded engineering fields. There are specialties of course, but nobody worries that when they hire a mechanical engineer someone needs to make sure the engineer can make designs with a particular brand of hex bolt because the last 5 years of the company’s designs all use that brand.

            • pron a day ago ago

              If a language offered a significant competitive advantage, such an analysis wouldn't be necessary. Someone would capitalise on it, and others would follow. There are selective pressures in software. Contingencies play an outsized role only when the intrinsics don't.

              • johncolanduoni a day ago ago

                My point is that for most of the software world, selective pressures are much weaker than things like switching costs and ecosystem effects. The activation energy for a new tech stack is massive - so it's very easy to get stuck in local maxima for a long time.

                • pron 13 hours ago ago

                  You call it weak selective pressures, but another way of saying it is low fitness advantage. And we can see that because the programming language landscape is far from static, and newcomers do gain adoption very quickly every now and then.

                  In fact, when we look at the long list of languages that have become super-popular and even moderately popular - including languages that have grown only to later shrink rather quickly - say Fortran, COBOL, C, C++, JavaScript, Java, PHP, Python, Ruby, C#, Kotlin, Go, TypeScript, we see languages that are either more specific to some domains or more general, some reducing switching costs (TS, Kotlin) some not, but we do see that the adoption rate is proportional to the language's peak market share, and once the appropriate niche is there (think of a possibly new/changed environment in biological evolution) we see very fast adoption, as we'd expect to see from a significant fitness increase.

                  So given that many languages displace incumbents or find their own niches, and that the successful ones do it quickly, I think that the most reasonable assumption to start with when a language isn't displaying that is that its benefits just aren't large enough in the current environment(s). If the pace of your language's adoption is slow, then: 1. the first culprit to look for is the product-market fit of the language, and 2. it's a bad sign for the language's future prospects.

                  I guess it's possible for something with a real but low advantage to spread slowly and reach a large market share eventually, but I don't think it's ever happened in programming languages, and there's the obvious risk of something else with a bigger advantage getting your market in the meantime.

          • pjmlp a day ago ago

            As proven in several cases, it is mostly caused by management not willing to keep the required investment to make it happen.

            Projects like Midori, Swift, Android, MaximeVM, GraalVM, only happen when someone high enough is willing to keep it going until it takes off.

            When they fail, usually it is because management backing felt through, not because there wasn't a way to sort out whatever was the cause.

            Even Java had enough backing from Sun, IBM, Oracle and BEA during its early uncertainty days outside being a language for applets, until it actually took off on server and mobile phones.

            If Valhala never makes it, it is because Oracle gave up funding the team after all these years, or it is impossible and it was a waste of money?

        • lerno a day ago ago

          Unfortunately Swift is a mess of a language, trying to put as many language features in there as possible. While still not getting close to being a good replacement for Objective-C. AND it's the slowest language to compile among languages with a substantial adoption.

          It's just pig-headedness by Apple, nothing more.

          • pjmlp a day ago ago

            I agree with the toolchain problems, the rest we don't need another Go flavour, with its boilerplate and anti language research culture.

            • lerno 20 hours ago ago

              It is well known that Swift set out in design without any prior knowledge of the language it was replacing (Objective-C), with only the most junior in the team having used it to any greater extent.

              Instead Swift was designed around the use-cases the team was familiar with, which would be C++ and compilers. Let's just say that the impedance between that and rapid UI development was pretty big. From C++ they also got the tolerance for glacial compile times (10-50 times as slow as compiling the corresponding Objective-C code)

              In addition to that they did big experiments, such as value semantics backed by copy-on-write, which they thought was cool, but is – again – worthless in terms of the common problem domains.

              Since then, the language's just been adding features at a speed even D can't match.

              However, one thing the language REALLY GETS RIGHT, and which is very under-appreciated, is that they duplicated Objective-C's stability across API versions. ObjC is best in class when it comes to the ability to do forward and backwards compatibility, and Swift has some AWESOME work to make that work despite the difficulties.

    • dayvster 2 days ago ago

      Segfaults go brrr.

      All jokes aside, it doesn’t actually take much discipline to write a small utility that stays memory safe. If you keep allocations simple, check your returns, and clean up properly, you can avoid most pitfalls. The real challenge shows up when the code grows, when inputs are hostile, or when the software has to run for years under every possible edge case. That’s where “just be careful” stops working, and why tools, fuzzing, and safer languages exist.

      • KingOfCoders 2 days ago ago

        My assumption is a small utility becomes a big utility.

      • uecker a day ago ago

        And a segfault would be worse than a panic, data corruption or out of memory access are the problems. But in reality, most C programs I use daily have never crashed in decades.

    • dev_l1x_be 2 days ago ago

      The amount of seggfaults I have seen with Ghostty did not raise my spirits.

      • dpatterbee 2 days ago ago

        I've had at least one instance of Ghostty running on both my work and personal machine continuously since I first got access to the beta last November, and I haven't seen a single segfault in that entire time. When have you seen them?

        • metaltyphoon 2 days ago ago

          Look at the issue tracker and its history too.

        • dmit a day ago ago

          I've seen the amount of effort Mitchell &co put into ensuring memory safety of Ghostty in the 1.2 release notes, but after upgrading I am still afraid to open a new pane while there's streaming output in the current one because in 1.1.3 that meant a crash more often than not.

        • mr90210 2 days ago ago

          Google: "wikipedia Evidence of absence"

          Also, https://github.com/ghostty-org/ghostty/issues?q=segfault

          • dpatterbee 2 days ago ago

            So Ghostty was first publicly released on I think December 27th last year, then 1.0.1, 1.1.0, 1.1.1, and 1.1.2 were released within the next month and a half to fix bugs found by the large influx of users, and there hasn't been a segfault reported since. I would recommend that users who are finding a large number of segfaults should probably report it to the maintainers.

      • hnaccount19293 a day ago ago

        Bun is much worse in this regard too.

        • johncolanduoni a day ago ago

          It makes me sad, because they demonstrated JavaScriptCore is shockingly better than V8 for node-likes. The Typescript compiler (which like basically any non-trivial typechecker is CPU bound) is consistently at least 2x faster with Bun on large projects I've worked on.

          • pjmlp a day ago ago

            When Typescript finishes their Go rewrite that will become irrelevant, and I rather have the compiler from the same people that design the language.

            • johncolanduoni a day ago ago

              For that example sure, and admittedly the entire JavaScript/TypeScript processing ecosystem is moving in that direction. But the TypeScript compiler is not the only CPU-bound JavaScript out there.

              • pjmlp a day ago ago

                There are plenty of memory safe compiled languages to rewrite that JavaScript into.

      • neerajk 2 days ago ago

        segfaults raise my belief in spirits

        • greesil 2 days ago ago

          Possibly a good Halloween costume idea to go as a segfault. It would scare some people.

      • txdv 2 days ago ago

        I haven't seen a single one.

    • johncolanduoni a day ago ago

      Yeah, I often wonder if people who have this attitude have ever tried to run a non-trivial C program they wrote with the clang sanitizers on. A humbling experience every time.

    • jmull a day ago ago

      I think the problem the practical programmer has with a statement like this is the implication that only certain languages require some basic understanding and a bit of discipline to avoid CVEs.

      Rust's model has a strict model that effectively prevents certain kinds of logic errors/bugs. So that's good (if you don't mind the price). But it doesn't address all kinds of other logic errors/bugs. It's like closing one door to the barn, but there are six more still wide open.

      I see rust as an incremental improvement over C, which comes at quite a hefty price. Something like zig is also an incremental improvement over C, which also comes at a price, but it looks like a significantly smaller one.

      (Anyway, I'm not sure zig is even the right comp for rust. There are various languages that provide memory safety, if that's your priority, which also generally allow dropping into "unsafe" -- typically C -- where performance is needed.)

      • estebank a day ago ago

        > But it doesn't address all kinds of other logic errors/bugs. It's like closing one door to the barn, but there are six more still wide open.

        Could you point at some language features that exist in other languages that Rust doesn't have that help with logic errors? Sum types + exhaustive pattern matching is one of the features that Rust does have that helps a lot to address logic errors. Immutability by default, syntactic salt on using globals, trait bounds, and explicit cloning of `Arc`s are things that also help address or highlight logic bugs. There are some high level bugs that the language doesn't protect you from, but I know of now language that would. Things like path traversal bugs, where passing in `../../secret` let's an attacker access file contents that weren't intended by the developer.

        The only feature that immediately comes to mind that Rust doesn't have that could help with correctness is constraining existing types, like specifying that an u8 value is only valid between 1 and 100. People are working on that feature under the name "pattern in types".

        • jmull a day ago ago

          IMO, simplicity is the number one feature. The developer should spend their attention on the problem space as much as possible, and on the solution space as little as possible.

          There's a complexity cost to adding features, and while each one may make sense on its own, in aggregate they may collectively burden the developer with too much complexity.

          • ViewTrick1002 18 hours ago ago

            The question is, what is simplicity?

            Go tries to hide the issues, until a data loss happens because it has had trouble dealing with non-UTF8 filenames and Strings are by convention UTF8 but not truly and some functions expect UTF8 while others can work with any collection of bytes.

            https://blog.habets.se/2025/07/Go-is-still-not-good.html

            Or the Go time library which is a monster of special cases after they realized they needed monotonic clocks [1] but had to squeeze it into the existing API.

            https://pkg.go.dev/time

            Rust is on the other end of the spectrum. Explicit over implicit, but you can implicitly assume stuff works by panicking on these unexpected errors. Making the problem easy to fix if you stumble upon it after years of added cruft and changing requirements.

            [1]: https://github.com/golang/go/issues/12914

      • dmytrish a day ago ago

        Actually, the strong type system is often why people like to write Rust. Because encoding logic invariants in it also helps to prevent logic bugs!

        There is a significant crowd of people who don't necessarily love borrow checker, but traits/proper generic types/enums win them over Go/Python. But yes, it takes significant maturity to recognize and know how to use types properly.

    • zem 2 days ago ago

      that is the precise point at which the article lost me. ironically it's often good programmers who don't "get" the benefit of building memory management and discipline into the language, rather than leaving it to be a cognitive burden on every programmer.

    • zwnow 2 days ago ago

      "Actually memory management is easy, you just have to...."

      - Every C programmer I've talked to

      No its not, if it was that easy C wouldn't have this many memory related issues...

      • r_lee 2 days ago ago

        It may be easy to do memory management, but it's not too easy to detect if you've made a fatal mistake when such mistakes won't cause apparent defects

        avoiding all memory management mistakes is not easy, and the bigger the codebase becomes, the more exponential the chance for disaster gets

        • zwnow 2 days ago ago

          Absolutely, big factor is undefined behavior which makes it look like everything works. Until it doesn't. I quit C long ago because I don't want to deal with manual memory management in any language. I was overwhelmed by Zigs approach as well. Rust is pretty much the only language making it bearable to me.

    • quotemstr a day ago ago

      > The words of every C programmer who created a CVE.

      Much of Zig's user base seems to be people new to systems programming. Coming from a managed code background, writing native code feels like being a powerful wizard casting fireball everywhere. After you write a few unsafe programs without anything going obviously wrong, you feel invincible. You start to think the people crowing about memory safety are doing it because they're stupid, or, cowards, or both. You find it easy to allocate and deallocate when needed: "just" use defer, right? Therefore, it someone screws up, that's a personal fault. You're just better, right?

      You know who used to think that way?

      Doctors.

      Ignaz Semmelweis famously discovered that hand-washing before childbirth decreased morality by an order of magnitude. He died poor and locked in an asylum because doctors of the day were too proud to acknowledge the need to adopt safety measures. If mandatory pre-surgical hand-washing step prevented complication, that implied the surgeon had a deficiency in cleanliness and diligence, right?

      So they demonized Semmelweis and patients continued for decades to die needlessly. I'm sure that if those doctors had been on the internet today, they would say, as the Zig people do say, "skill issue".

      It takes a lot of maturity to accept that even the most skilled practitioners of an art need safety measures.

      • lerno a day ago ago

        I can't speak for Zig users, but an interesting alternative to just new/delete or malloc/free and various garbage collection strategies is pervasive use of temp allocation using arenas, such as Jai and Odin's temp allocators (essentially frame allocators) and C3's stack-like temp allocator. Zig also favours using arenas, but more ad hoc.

        What happens in those cases is that you drop a whole lot of disorganized dynamic and stack allocations and just handle them in a batch. So in all cases where the problem is tracking temporary objects, there's no need to track ownership and such. It's a complete non-problem.

        So if you're writing code in domains where the majority of effort to do manual memory management is tracking temporary allocations, then in those cases you can't really meaningfully say that because Rust is safer than a corresponding malloc/free program in C/C++ it's also safer than the C3/Jai/Odin/Zig solution using arenas.

        And I think a lot of the disagreement comes from this. Rust devs often don't think that switching the use of the allocator matters, so they argue against what's essentially a strawman built from assumed malloc/free based memory patterns that are incorrect.

        ON THE OTHER HAND, there are cases where this isn't true and you need to do things like safely passing data back and forth between threads. Arenas doesn't help with that at all. So in those cases I think everyone would agree that Rust or Java or Go is much safer.

        So the difference between domains where the former or the latter dominates needs to be recognised, or there can't possibly be any mutual understanding.

        • johncolanduoni a day ago ago

          If you're allocating most things from a set of arenas alive for the same scope, Rust's borrow checker complexity almost entirely fades away. You'll have one lifetime for all inputs and outputs of your functions, so the inferred lifetimes will always be correct. If you have multiple arenas being allocated from with different scopes, you're asking for trouble with the Zig model while the Rust borrow checker will keep which data is from which arena straight.

        • pjmlp 19 hours ago ago

          Basically Pascal's Mark() and Release() calls.

          http://www.3kranger.com/HP3000/mpeix/doc3k/B3150290023.10194...

          What is old is new again.

        • quotemstr a day ago ago

          If arena allocators were a panacea, Subversion and Apache would be safer than your typical C program, yes?

    • markphip 2 days ago ago

      Came here to add the same comment. Had it on my clipboard already to post. You said it better

    • naikrovek 2 days ago ago

      are you saying that such understanding isn't enough or that every C programmer who said that didn't understand those things?

      C and Zig aren't the same. I would wager that syntax differences between languages can help you see things in one language that are much harder to see in another. I'm not saying that Zig or C are good or bad for this, or that one is better than the other in terms of the ease of seeing memory problems with your eyes, I'm just saying that I would bet that there's some syntax that could be employed which make memory usage much more clear to the developer, instead of requiring that the developer keep track of these things in their mind.

      Even if you must manually annotate each function so that some metaprogram that runs at compile time can check that nothing is out of place could help detect memory leaks, I would think. or something; that's just an idea. There's a whole metaprogramming world of possibilities here that Zig allows that C simply doesn't. I think there's a lot of room for tooling like this to detect problems without forcing you to contort yourself into strange shapes simply to make the compiler happy.

      • kstenerud 2 days ago ago

        > are you saying that such understanding isn't enough or that every C programmer who said that didn't understand those things?

        Probably both. They're words of hubris.

        C and Zig give the appearance of practicality because they allow you to take shortcuts under the assumption that you know what you're doing, whereas Rust does not; it forces you to confront the edge cases in terms of ownership and provenance and lifetime and even some aspects of concurrency right away, and won't compile until you've handled them all.

        And it's VERY frustrating when you're first starting because it can feel so needlessly bureaucratic.

        But then after awhile it clicks: Ownership is HARD. Lifetimes are HARD. And suddenly when going back to C and friends, you find yourself thinking about these things at the design phase rather than at the debugging phase - and write better, safer code because of it.

        And then when you go back to Rust again, you breathe a sigh of relief because you know that these insidious things are impossible to screw up.

      • capitol_ 2 days ago ago

        Just understanding the rules are not enough, you also need to be consistently good so that you never make a mistake that gets into production.

        On both your average days and your bad days.

        Over the 40 to 50 years that your carer lasts.

        I guess those kind of developers exist, but I know that I'm not one of them.

  • Imustaskforhelp 2 days ago ago

    What are your thoughts on nim, odin and v-lang, D-lang?

    I feel like I am most interested about nim given how easy it was to pick up and how interoperable it is with C and it has a garbage collector and can change it which seems to be great for someone like me who doesn't want to worry about manual memory management right now but maybe if it becomes a bottleneck later, I can atleast fix it without worrying too much..

    • dayvster 2 days ago ago

      I have not given any of those 3 a fair enough shot just yet to make a balanced and objective decision.

      Out of all of them from what little I know and my very superficial knowledge Odin seems the most appealing to me, it's primary use case from what I know is game development I feel like that could easily pivot into native desktop application development was tempted to make a couple of those in odin in the past but never found the time.

      Nim I like the concept and the idea of but the python-like syntax just irks me. haha I can't seem to get into languages where indentation replaces brackets.

      But the GC part of it is pretty neat, have you checked Go yet?

      • Imustaskforhelp a day ago ago

        I am a big fan of golang lol. Golang might be the language that I can love the most, portable, easy to write, stdlib that's goated, fast to compile with, and a great ecosystem!

        But I like nim in the sense that I feel sometimes in golang that I can't change its GC and so although I do know that for most things it wouldn't be a breaker.

        but still, I sometimes feel like I should've somewhat freedom to add memory management later without restarting from scratch or something y'know?

        Golang is absolutely goated. This was why I also recommended V-lang, V-lang is really similar to golang except it can have memory management...

        They themselves say that on the website that IIRC if you know golang, you know 70% V-lang

        I genuinely prefer golang over everything but I still like nim/ V-lang too as fun languages as I feel like their ecosystem isn't that good even though I know that yes they can interop with C but still...

      • O-stevns 2 days ago ago

        Odin has no primary use case, it just happens that a lot of the members in the community have made or are interested in game making

        • Imustaskforhelp a day ago ago

          My understanding of odin was that its good for data oriented.

          I haven't really looked into odin except joining their discord and asking them some questions.

          it seems that aside from some normal syntax, it is sort of different from golang under the hood as compared to V-lang which is massively inspired by golang

          After reading the HN post of sqlite which recommended using sqlite as a odt or some alternative which I agreed. I thought of creating an app in flutter similar to localsend except flutter only supports C esq and it would've been weird to take golang pass it through C and then through flutter or smth and I gave up...

          I thought that odin could compile to C and I can use that but it turns out that Odin doesn't really compile to C as compared to nim and v-lang which do compile to C.

          I think that nim and v-lang are the best ways to write some app like that though with flutter and I am now somewhat curious as to what you guys think would be the best way of writing highly portable apps with something personally dev-ex being similar to golang..

          I have actually thought about using something like godot for this project too and seeing if godot supports something like golang or typescript or anything really. Idk I was just messing around and having a bit of fun lol i think.

    • pjmlp a day ago ago

      From those only Nim and D are interesting.

      We don't need yet another language with manual memory management in the 21st century, and V doesn't look that would ever be that relevant.

      • Imustaskforhelp a day ago ago

        V is also similar to nim tho.

        V is also similar to golang in syntax, something that I definitely admire tbh.

        I am interested about nim and V more tbh as compared to D-lang

        In fact I was going to omit D-lang from my comment but I know that those folks are up to something great too and I will try to look into them more but nim defintely peaks my interests as a production ready language-ish imo as compared to V-lang or even D-lang

  • Nevermark 2 days ago ago

    > So when it comes to memory management there are two [THREE] terms you really need to know, [THE REGISTER BANK,] the stack and the heap.

    Edits mine.

    I like to keep the spacetime topologies complete.

    Constant = time atom of value.

    Register = time sequence of values.

    Stack = time hierarchy of values.

    Heap = time graph of values.

  • rawkode 2 days ago ago

    Why does a personal blog need so many advertising options?

    • ModernMech 2 days ago ago

      Yeah this whole blog is sus. Author claims to have been around for 17 years, doesn't have a single project of note and makes naive claims. Github history has thousands of commits per year every single day to private repos, yet very little public code or record to offer credibility. Not clear where they work or what they work on. Makes inflammatory claims about hot-topic languages. Throws up ads on the blog. Personally posts blog to HN on a relatively new account, rather than it organically finding its way here. Sorry I'm not buying it.

      He seems to know what he's doing, from the author's Twitter:

        Post something slightly mentioning rust in r/cpp, Rust evangelists show up, post something slightly mentioning rust in r/zig, Rust evangelists show up. How is this not a cult?
      • Tade0 a day ago ago

        > Author claims to have been around for 17 years, doesn't have a single project of note and makes naive claims.

        Plenty of such people out there.

        This guy appears to just personally dislike Rust for reasons undisclosed and tries to rationalize it via posts like this one.

        It's like with this former coworker of my former coworker who was really argumentative, seemingly for the sake of it. I did some digging and found that his ex left him and is now happily married.

        Turns out that when he was criticizing the use of if-else in Angular templates what he was really thinking about was "if someone else".

      • hnlmorg a day ago ago

        What you’ve described there is a 90% match for most people in tech.

  • pjmlp 2 days ago ago

    I love the irony to see the C crowd rediscovering Modula-2 and Object Pascal safety, through Zig.

    Apparently it isn't programming with a straightjacket any longer, like on Usenet discussions.

  • vanyle a day ago ago

    For CLI tools, the program usually only executes for a few seconds and then returns. In this context, you don't even need arena allocators or any memory management at all. You can write the tool in C with malloc and let the OS free the memory at the end without worry.

    You could argue with the reasoning that C feels more practical than Zig for real-world CLI tools.

    The argument provided by the author feels a bit besides the point.

  • daft_pink a day ago ago

    I think the underlying question is why move to Zig from a C variant?

    There is a lot of research showing that a high percentage of security bugs are from memory safety issues across many different studies. I believe this is why people are pushing moving to Rust.

    However, if you don’t get the memory safety in Zig. Why bother moving from your existing coding language? Why not just not learn a new language and code where you are?

    • mattwilsonn888 a day ago ago

      I don't use Zig, but I can answer your questions:

      Because Zig is a better language across the board.

      And that includes safety. You can have a language that doesn't do heavy static-analysis like Rust which still makes safety a lot easier than C/C++.

      Memory safety is not even a flaw of C/C++, it's a tradeoff. That being said, even if memory-safety was a 'feature' (rather than a tradeoff, and yes, Rust did a better job minimizing the trade than GC or FP languages), it's not the only feature.

    • bsder a day ago ago

      > I think the underlying question is why move to Zig from a C variant?

      Null pointers disallowed by default. Slices. Superb cross-compilation. Easy C interop. Comptime instead of C preprocessor.

      There are lots more.

      The problem Rust is up against is that the number of people who want Rust simply because of "strict typing" far, far, far outnumbers those who care about safety or speed. And that leads to the issue that most people really should be using a GC language like OCaml rather than Rust.

      Unfortunately, the OCaml ecosystem ... :(

  • stonemetal12 2 days ago ago

    The fact that your app crashes when you run out of stack is a compiler bug, not a feature. Memory is memory. The fact that languages in the 40s split in it to stack and heap, doesn't make it a foundational mathematical law.

    Yes, safety isn't correctness but if you can't even get safety then how are you supposed to get correctness?

    For small apps Zig probably is more practical than Rust. Just like hiring an architect and structural engineers for a fence in your back yard is less practical than winging it.

  • 2 days ago ago
    [deleted]
  • benashford 2 days ago ago

    Aren't these two points contradictory? Forgive me if I'm misunderstanding.

    > Rust’s borrow checker is a a pretty powerful tool that helps ensure memory safety during compile time. It enforces a set of rules that govern how references to data can be used, preventing common programming memory safety errors such as null pointer dereferencing, dangling pointers and so on. However you may have notice the word compile time in the previous sentence. Now if you got any experience at systems programming you will know that compile time and runtime are two very different things. Basically compile time is when your code is being translated into machine code that the computer can understand, while runtime is when the program is actually running and executing its instructions. The borrow checker operates during compile time, which means that it can only catch memory safety issues that can be determined statically, before the program is actually run. > > This means that basically the borrow checker can only catch issues at comptime but it will not fix the underlying issue that is developers misunderstanding memory lifetimes or overcomplicated ownership. The compiler can only enforce the rules you’re trying to follow; it can’t teach you good patterns, and it won’t save you from bad design choices.

    This appears to be claiming that Rust's borrow checker is only useful for preventing a subset of memory safety errors, those which can be statically analysed. Implying the existence of a non-trivial quantity of memory safety errors that slip through the net.

    > The borrow checker blocks you the moment you try to add a new note while also holding references to the existing ones. Mutability and borrowing collide, lifetimes show up, and suddenly you’re restructuring your code around the compiler instead of the actual problem.

    Whereas this is only A Thing because Rust enforces rules so that memory safety errors can be statically analysed and therefore the first problem isn't really a problem. (Of course you can still have memory safety problems if you try hard enough, especially if you start using `unsafe`, but it does go out of its way to "save you from bad design choices" within that context.)

    If you don't want that feature, then it's not a benefit. But if you do, it is. The downside is that there will be a proportion of all possible solutions that are almost certainly safe, but will be rejected by the compiler because it can't be 100% sure that it is safe.

  • ranger_danger 2 days ago ago

    IMO, as a C++ developer, Swift makes the most sense to me if I were looking for a safer alternative.

    I think people prefer what's familiar to them, and Swift definitely looks closer to existing C++ to me, and I believe has multiple people from the C++ WG working on it now as well, supposedly after getting fed up with the lack of language progress on C++.

    The most recent versions gained a lot in the way of cross-platform availability, but the lack of a native UI framework and its association with Apple seem to put off a lot of people from even trying it.

    I wish it was a lot more popular outside of the Apple ecosystem.

  • massung a day ago ago

    > Seasoned Rust coders don’t spend time fighting the borrow checker...

    Experienced Rust coders aren't going to find themselves in various borrow checker (and lifetime) pitfalls that newbies do, sure.

    That said, the borrow checker and lifetime do cause problems for even experienced Rust programmers. Not because they don't understand memory management, lifetimes, etc. But because they don't - yet - fully understand the problem being solved.

    All programs are an evolutionary process of developing a solution to a problem (or many problems). You think one thing, code it up, realize you missed something or didn't fully grok the issue, pivot, etc.

    Rust does a great job in the compiler of letting the user know if they've borked something. But often times a refactor/fix in C/D/Zig due to learned (or new) requirements is just a tweak, while in Rust it becomes a major overhaul because now something needs to be `mut` or have a lifetime added to it. I - personally - consider that "fighting" the borrow checker, regardless of how helpful (or correct) it also is.

  • illuminator83 2 days ago ago

    Actually, developers are idiots. Everyone is. Some just don't know it or won't admit it.

    I once joined a company with a large C/C++ codebase. There I worked with some genuinely expert developers - people who were undeniably smart and deeply experienced. I'm not exaggerating and mean it.

    But when I enabled the compiler warnings (which annoyed them) they had disabled and ran a static analyzer over the codebase for the first time, hundreds of classic C bugs popped up: memory leaks, potential heap corruptions, out-of-bounds array accesses, you name it.

    And yet, these same people pushed back when I introduced things like libfmt to replace printf, or suggested unique_ptr and vector instead of new and malloc.

    I kept hearing:

    "People just need to be disciplined allocations. std::unique_ptr has bad performance" "My implementation is more optimized than some std algorithm." "This printf is more readable than that libfmt stuff." etc.

    The fact is, developers, especially the smart ones probably, need to be prevented from making avoidable mistakes. You're building software that processes medical data. Or steers a car. Your promise to "pay attention" and "be careful" cannot be the safeguard against catastrophe.

    • Cloudef 2 days ago ago

      To be honest, the generated machine code / assembly is often more readable than the actual c++ code in c++ stdlibs. So I can sympathize with the "This printf is more readable than that libfmt stuff." comment :)

      • illuminator83 a day ago ago

        Oh, they were not talking about the implementation of these things. Just the the user side:

        printf("Error: File `%s` in batch %d failed.", file.c_str(), batch) vs fmt::print("Error: File `{}` in batch {} failed.", file, batch)

        One of which is objectively safer and more portable than the other. They didn't care. "I like what I've been doing for the last 20 years already better because it looks better.". "No Its not because I'm just used to it." "If you are careful it is just as safe. But you gotta know what you are doing."

        And best of all - classic elitism:

        "If you are not smart enough to do it right with printf, maybe you shouldn't be a C++ programmer. Go write C# or something instead."

        The same person was not smart enough to do it right in many places as I've proven with a static analyzer.

        • Cloudef a day ago ago

          Yeah, its frightingly common CI not doing static analysis checks on C/C++ code. The compiler defaults being really bad doesn't help either. The nice thing about zig is that it defaults to "safe" behaviour, and even if you use it as C/C++ compiler it has saner defaults and compiles with ubsan.

          You can guide compiler to check printf style format strings using __attribute__((format)) btw, also checks you are not using a variable as a format string

  • NielsAndersen67 a day ago ago

    I have been writing Rust code for 3.5 years. I never fight the borrow checker. The ownership rules are a blessing, when ever the compiler yells at me, then I know I am doing something that would have caused a seg fault i. C. It took a little while to get used to Rusts syntax, but once I got it, it was the best programming language I have ever used. It is just so beautiful how it enables multi threading and ensures that all errors are handled.

  • kennykartman 2 days ago ago

    If I had a penny for every time I heard that devs are not idiots, I'd be billionaire.

    It's true, but devs are not infallible and that's the point of Rust. Not idiots, not infallible either.

    IMO admitting that one can make mistakes even if they don't think they have is a sign of an experienced and trustworthy developer.

    It's not that Rust compiler engineers think that devs are idiots, in fact you CAN have footguns in Rust, but one should never use a footgun easily, because that's how you get security vulnerabilities.

  • carodgers a day ago ago

    This really misses a major point. If you write something in Zig, you can have some confidence in the stability of the program, if you trust yourself as a developer. If someone else writes something else in Zig, you have to live with the possibility that they have not been as responsible as you would have preferred.

    • aidenn0 a day ago ago

      Indeed. The other day I was messing around with making various associative data structures in Zig.

      I stole someone else's benchmark to use, and at one point I ran into seriously buggy behavior on strings (but not integers) that wasn't caught at the point where it happened early even with -Odebug.

      Turns out the benchmark was freeing the strings before it finished performing all of the operations on the data structure. That's the sort of thing that Rust makes nearly impossible, but Zig didn't catch at all.

    • mattwilsonn888 a day ago ago

      This is true for every language. Logic bugs exist. I'll take good OS process isolation over 'written-in-Rust' though I wouldn't mind both.

      That being said, you've missed the point if you can't understand that safety comes at a real cost, not an abstract or 'by any means necessary' cost, but a cost as real as the safety issues.

  • tonetegeatinst 2 days ago ago

    As far as my understanding of zig goes....it can compile into C....so if you really want secure C code you can compile zig into C?

    • dayvster 2 days ago ago

      Not quite, it can translate C into zig using the `translate-c` command that it comes with. But it compiles directly into machine code

      • osmsucks 2 days ago ago

        There is a C backend, so you can also compile Zig into C if you want.

        • dayvster 2 days ago ago

          yea but, that's extremely edge case, or at least I have not yet encountered a need for that personally.

    • Cloudef 2 days ago ago

      Zig can compile into C, but it's not portable C

    • Ar-Curunir 2 days ago ago

      While Zig prevents certain kinds of memory safety issues that C does not, it still suffers from memory-safety issues not found in safe Rust.

  • tcfhgj 2 days ago ago

    building houses or power lines without regulations feels more practical as well

  • einpoklum 2 days ago ago

    Ah, sweet flame war fuel.

    Maybe we'll even get a tabs vs. spaces article next.

  • lerno a day ago ago

    I find some of Rust dev reactions to this article pretty embarrassing. As if memory safety was some holy grail only provided by Rust.

    Here is a bunch of more memory safe languages that are more popular than Rust: Python, Java, JS ... should I continue?

    But wait, there's more. Can Rust verify that arbitrary in-data is valid, like having contracts statically checked at compile time? It can't, and so then by the same logic as some people calling non-Rust languages "gibberish" for not having a borrow checker, should we call Rust "gibberish" because it can't check those invariants at compile time like C3 can do?

    No?

    Then get off that high horse.

    And by the way, my great fear is that we'll get more adoption by Rust while at the same time Rust is unable to improve the compile times. C++, Swift and Rust, the three horsemen of infamously long compile times.

    The borrow checker isn't the main problem, just like C++'s problems isn't complex template messages – it's that both takes so long to compile. Time you could spend reading and testing the code. Long compile times inhibits refactoring and cause bugs to stay unfixed.

    • simonask 20 hours ago ago

      The point about "gibberish" is getting at a fundamental misunderstanding that people have about Undefined Behavior.

      Rust's concept of "safety" really means "absence of Undefined Behavior". Lots of people don't seem to understand that C, C++, and Zig programs containing UB are gibberish - they are not C, C++, or Zig programs, but something else entirely. The key insight here is that in any language, UB invalidates the entire program. It no longer does what you think it does, your tests are all moot, and so on. But a lot of people seem to think that there is an acceptable amount of UB in any code base. There isn't.

      UB is a concept that exists for every language, even languages like Python, Java, C#, JavaScript, but those languages make it very hard to encounter accidentally.

      Before Rust, there was no way to guarantee the absence of UB without a significant runtime cost, so that's a very meaningful invention.

  • rubiquity 2 days ago ago

    This blog is atrocious from an ad standpoint and the recent flood of posts feels promotional and intentionally controversial. The articles are also devoid of any interesting perspectives. Are people actually reading this?

  • anon-3988 2 days ago ago

    i am sorry but how does point 1 and point 2 for safety work together? You don't want the program to corrupt your program but also does not want to immediately crash the moment some invariant is not being held?

    > Compile-time only: The borrow checker cannot fix logic bugs, prevent silent corruption, or make your CLI behave predictably. It only ensures memory rules are followed.

    Also not really true from my experience. There have been plenty of times where the borrow checker is a MASSIVE help in multithreaded context.

  • xwowsersx 2 days ago ago

    No shade here, just a genuine question: why run ads on a blog like this? A personal technical blog probably doesn't get a ton of traffic. So what's the point? I'm honestly curious.

  • quotemstr a day ago ago

    I'm still having a hard time understanding who is supposed to use Zig.

    If I don't need absolute best performance, I can use GC-ed systems like Node, Python, Go, OCaml, or even Java (which starts fast now thanks to Graal AOT) and enjoy both the safety and expressive power of using a high-level language. When I use a GCed language, I don't have to worry about allocation, lifetimes, and so on, and the user gets a plenty good experience.

    If I need the performance only manual memory management can provide (and this situation arises a lot less often than people think it does), I can justify spending the extra time expressing my thoughts in Rust, which will get me both performance and safety.

    Why would I go to the trouble of using Zig instead of Rust? Zig, like Rust, incurs a complexity and ecosystem cost. It doesn't give me safety in exchange. I put in about as much effort as I would into a Rust program but don't get anything extra back. (Same goes if you substitute "C++" for "Rust".)

    > All it took was some basic understanding of memory management and a bit of discipline.

    Is the idea behind Zig just that it's perfectly safe if you know what you're doing --- therefore using Zig is some kind of costly signal of competence? That's like someone saying free-solo-ing a cliff face is perfectly safe if you know what you're doing. Someone falls to his death? Skill issue, right?

    We have decades of experience showing that nobody, no matter how much "understanding" and "discipline" he has, can consistently write memory-safe code with manual memory management in a language that doesn't enforce memory safety rules.

    So what's the value proposition for Zig?

    Are you supposed to use it instead of something like Go or Python or AOT-Kotlin and spend more of your time dealing with memory than you would in one of these languages? Why?

    Or are you supposed to use it instead of Rust and get, what, slightly faster compile times, maybe? And no memory safety?

    • dmytrish a day ago ago

      So far, most of Zig enthusiasts look to me like people who get sugar rush from writing fast native code and are ignorant (i.e. newcomers to system programming) or arrogant (e.g. long time C programmers stubbornly stuck in their ways) enough to think that memory safety is just a question of not writing stupid bugs. Or luddites that think that programs must always be simple enough to get memory safety right.

      • pjmlp 19 hours ago ago

        Fits perfectly on my understand as well.

  • andrewshadura a day ago ago

    Does it?

  • buggymcbugfix 15 hours ago ago

    OP: Rust feels impractical. ATS: Hold my beer.

  • dpc_01234 a day ago ago

    The title is about CLI tools, then it seems like bunch of cope about borrow-checker-phobia.

    I would actually be interested in a honest comparison of a Rust CLI program using clap, duct and some other standard CLI handling libraries with their Zig equivalents.

    Show the code side by side, how much boilerplate each requires. Then compare how quickly they compile in debug and release mode, how fast they start, how big the binaries are after stripping, stuff like that.

  • bitwize a day ago ago

    Two words: Skill issue.

    The catgirls have no problems producing lots of great software in Rust. It seems more such software comes out every day, nya :3

  • iphone_elegance 2 days ago ago

    when I think of rust I think of beauties like this,

    self.last.as_ref().unwrap().borrow().next.as_ref().unwrap().clone()

    I know it can be improved but that's what I think of

    • Klonoar a day ago ago

      Without any context it’s impossible to tell if code needs to be that obtuse or if uou somehow built your way into a setup that you could’ve avoided. ;P

      • einpoklum a day ago ago

        GP is suggesting that one typically finds oneself in such a situation with idiomatic code. Even if it can be avoided with some effort, it will all too easily not be avoided.

  • MangoToupe 2 days ago ago

    [flagged]

    • simonask 2 days ago ago

      I’m not an idiot!

      However, 3 months ago me was clearly an idiot judging from the utter crap he wrote. Me in 3 months is also an idiot, he won’t get the greatness of these genius hacks I’m making.

      • Ygg2 2 days ago ago

        I'm not an idiot either. But past and future me get to be idiots from time to time. Alcohol and lack of sleep are a helluva mind cripplers.

    • dayvster 2 days ago ago

      [flagged]

  • Svoka a day ago ago

    [flagged]

  • moochmoochmooch 2 days ago ago

    [flagged]

    • dayvster 2 days ago ago

      I can guarantee you that none of it was written by ChatGPT or any other LLM.

      As for the Ads, even though it's my site, I'd urge you to turn on adblocker, pi-hole or anything like that, I won't mind.

      I have ads on there yes, but since I primarily write tech articles for a target audience of tech people you can imagine that most readers have some sort of adblocker either browser, network or otherwise.

      So my grand total monthly income from ads basically covers hosting costs and so on.

      • Cloudef 2 days ago ago

        [flagged]

        • astrange a day ago ago

          I think people have just ingested so much LLM they think it's normal to use bullet point lists in the middle of an essay.