Hacker News new | ask | show | jobs
by mattwilsonn888 272 days 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.

16 comments

> 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.

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.

> 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.

Buffer overruns are most common memory related RCE's. So bounds checking arrays/strings BY DEFAULT is needed.
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.
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...

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.
Not clear to me there's a correlation between hours worked and number of memory safety vulnerabilities
I think the implication is something like "overwork / fraying morale from long hours means shipping more bugs".
>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.

Modula-2 was already a step function in safety past C, but people did not care because it wasn't given away alongside UNIX.
> "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.

>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.

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.
> 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"

postfix

sqlite

billions of installations and relatively few incidents

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.

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.

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.
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.

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.

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.
What does that have to do with Zig though?
> 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.

> 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).

"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.

Public Safety Announcement: Lane assist does not relieve you from the burden of constant vigilance.
> 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.

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.

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.

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

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

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.
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.

> 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!

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.

The borrow checker is never a significant portion of compile times.
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.

> 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.

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?

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.
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.

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.

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.

> 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.

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.

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.

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.

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.

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.

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.
> 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.

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

> 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.

The tradeoff is between performance, safety and ergonomics. With GC languages you lose the first one.
> 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.

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.

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.

> 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.

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.

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.

> 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.

> 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.

> also because of the boxing

Not every GC boxes primitives. Most don't.

Sure. What about non primitives?
Go is middle-pack fast, not fast-fast.

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

*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.

> 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.

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.

> 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.

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.

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.

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.
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?

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.

>Safety is less ergonomic.

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

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.

It's not flawed. Ergonomics are correlated with complexity. If you can remove edge cases by giving up on correctness you can remove complexity.
How are chairs related to programming languages? Analogies are just made-up arguments.
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.

> 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.

> 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.

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...

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.
> 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.

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.
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

Not saying that Rust is necessarily easy to pick up, but hundreds of thousands of people use Rust without a PhD in any subject.
Try and appreciate the humor in what you're replying to without fully discounting the point of it.
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.