Live data from Hacker News

Rust Is Hard, Or: The Misery of Mainstream Programming

hirrolot.github.io

51–60 of 811 posts

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#51

Unpopular opinion: I find rust code unreadable. And I consider myself a polyglot. I am sure all those symbols have a special meaning but it's like perl to me. Just throw some random special characters and they all mean something.

I completely agree. I think the syntax looks awful, for one. This has put me off learning it completely.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#52

Earlier quoted context omitted.

Completely agree. I wrote a multithreaded compute-heavy program in Rust, semi-ported from a C++ version, and sidestepped async completely—just used old school thread primitives. It was delightful! Once I sorted out the data structures and messaging, the borrow checker and Send/Sync traits made implementation nearly trivial, and absolutely no memory corruption or accidental non-atomic clobbering. It took a bunch of ho…

I’m a Rust newbie. Mind if I ask: are you referring to using threads and locks and queues and such? Does Rust give you rope to hang yourself when doing it without async or does it continue to be very specific about forcing you to guarantee that you’re not going to run into races and whatnot?

Rust marks cross-thread shared memory as immutable in the general case, and allows you to define your own shared mutability constructs out of primitives like mutexes, atomics, and UnsafeCell. As a result you don't get rope to hang yourself with by default, but atomic orderings are more than enough rope to devise incorrect synchronizations (especially with more than 2 threads or memory locations). To quote an earlier post of mine:

In terms of shared-memory threading concurrency, Send and Sync, and the distinction between &T and &Mutex and &mut T, were a revelation when I first learned them. It was a principled approach to shared-memory threading, with Send/Sync banning nearly all of the confusing and buggy entangled-state codebases I've seen and continue to see in C++ (much to my frustration and exasperation), and &Mutex providing a cleaner alternative design (there's an excellent article on its design at http://cliffle.com/blog/rust-mutexes/).

My favorite simple concurrent data structure is https://docs.rs/triple_buffer/latest/triple_buffer/struct.Tr.... It beautifully demonstrates how you can achieve principled shared mutability, by defining two "handle" types (living on different threads), each carrying thread-local state (not TLS) and a pointer to shared memory, and only allowing each handle to access shared memory in a particular way. This statically prevents one thread from calling a method intended to run on another thread, or accessing fields local to another thread (since the methods and fields now live on the other handle). It also demonstrates the complexity of reasoning about lock-free algorithms (https://github.com/HadrienG2/triple-buffer/issues/14).

I find that writing C++ code the Rust way eliminates data races practically as effectively as writing Rust code upfront, but C++ makes the Rust way of thread-safe code extra work (no Mutex unless you make one yourself, and you have to simulate &(T: Sync) yourself using T const* coupled with mutable atomic/mutex fields), whereas the happy path of threaded C++ (raw non-Arc pointers to shared mutable memory) leads to pervasive data races caused by missing or incorrect mutex locking or atomic synchronization.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#53
post #3

Rust isn't hard. Programming is hard. Rust just points out failure states before you encounter them in production.

I enjoy Rust, but it's not that simple. It really is more work to accomplish certain tasks in Rust than many other languages even when what you're doing is safe. The narrative that "Rust isn't hard" is getting tiresome, and I say this as someone who writes a lot of Rust. Let's be honest that Rust can be harder than many other programming languages in many ways, but those of us who use it believe the upsides and trade…

Rust isn't hard for the things you try to solve in Rust.

The author compares Rust code with Go code. Those two languages serve entirely different purposes, with entirely different mechanisms behind it.

Go does what the author does with ease because the runtime fixes all the complicated parts for you. You tell Go what you want and it'll try to solve all the memory management/threading/memory safety issues for you, usually succeeding.

Rust doesn't do that. Rust expects you not just to tell it what you want, but also how you want it to happen.

I think comparisons between Rust and Go/C#/Java are what will really trip up a beginner. Rust has a lot of nice features found in higher level languages, but it's decidedly not a higher level language. Rust operates in the space of C and C++, where a small mistake can cause memory corruption no debugger will ever be able to unravel, but where a well placed byte of padding can accelerate a program by as much as 30 percent.

I think the difficulty in Rust lies in that it will enforce correctness. Competing languages are less strict about that, especially when it comes to threading. You tell them a piece of memory is safe to use across thread boundaries and they'll believe you, and most of the time you can rely on race conditions not screwing you over perfectly well. A C program can be short, fast, and clear, as long as you leave out the error checking and resource management in case of failures; with Rust you often don't get that luxury. Writing correct code is a slow, tedious, painful experience, and in Rust you'll have to live with that pain (unless you throw around unsafe{} everywhere).

I believe that teaching programming should follow a bottom-up approach, but many others disagree. If you've dabbled in assembly, done some multi threaded C(++) and experienced the challenges in low-level code, Rust should be enjoyable enough to learn after cursing at the borrow checker a bunch of times. If you're a top-down learner, though, you'll run face-first into low-level problems and their complexities for seemingly no good reason.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#54

I personally believe that Rust is an exceptional language and it’s ahead of its time. Seriously, can you think of any other language with as incredible type system, incredible tooling, incredible performance, incredible package management and general package quality, incredible compilation target support, and practically no few backwards-compatibility quirks? But Rust is a really bad general-purpose language. Because…

Although I agree with almost everything you said, I still feel rust is a general purpose language.

Most programming projects are single thread, not async, and if you aren't juicing for performance, is pretty easy to write. Even in rust.

I think what makes writing rust for general purpose projects hard, is knowing you can do something better that doesn't have to be better.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#55

Rust does not have to be this hard. Most of the pain here come from the unholy trifactor: combining async, lifetimes and dynamic dispatch with trait object closures; which is indeed very awkward in practice. Async support is incredibly half-baked. It was released as an MVP, but that MVP has not improved notably in almost three years. There are lots of ideas, some progress on the fundamental language features required…

In your experience what languages would you say handle async well? Genuinely curious. I’ve only ever done JS professionally for a decade but started branching out into python, rust, and kotlin due to personal projects.

Interestingly, I've become a big fan of node's single-threaded "one big loop" model, which means multitasking is cooperative instead of preemptive. This strikes me as more honest, somehow. It doesn't distract you with abstractions (like threads) that don't make sense in this context. Most production workloads these days will be a docker process assigned to (at best) a single sticky core/thread on a blade somewhere - so in terms of resources, node is quite honest about what you actually have to work with. (This as opposed to, say, a Java process, which wants to believe it has control over an entire physical server CPU, and when you run it in a docker process, you're just exercising virtualization overhead if you use Thread, etc.)

That said, if you have a physical server, Java is quite good, especially with the upcoming Project Loom improvements. The langspec and vmspec have gotten fat the last 20 years, but at least those documents exist. Plus there is OpenJDK which is a great enabler and calmer of nerves; there's a reason so many alt langs target the JVM, and they are good. Groovy, Clojure, Kotlin, Scala are all first-rate languages, IMHO. And with projects like Quarkus you can more easily build native executables that bundle the JRE and make distribution very Rust-like.

Another environment I like specifically for async operation, but mostly by reputation, is Erlang and it's BEAM VM. Erlang itself is such an interesting language, being dynamic, functional, immutable, without traditional control structures (!) but relying heavily on recursion and pattern matching, and of course the "actor model" and extremely lightweight "processes" was invented here (and promptly ported to elsewhere, as with Akka). It was also created by one of the nicest human beings I've ever experienced, Joe Armstrong, may he rest in peace.

IANALL so YMMV.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#56

Earlier quoted context omitted.

I enjoy Rust, but it's not that simple. It really is more work to accomplish certain tasks in Rust than many other languages even when what you're doing is safe. The narrative that "Rust isn't hard" is getting tiresome, and I say this as someone who writes a lot of Rust. Let's be honest that Rust can be harder than many other programming languages in many ways, but those of us who use it believe the upsides and trade…

I'm in the same boat, I spend a bit of my working day writing in Rust .. it's a great language but it's very cumbersome and I find it suffers form poor ergonomics, like it's annoying to type

I find it enjoyable to type for the most part. Explicit type casts aren't a treasure or anything, but then I think about why I am doing it and I can't really complain.

I feel you, but, my experience differs in the end I guess. To be fair turbofishes we're something I discovered by intuition, so maybe I'm a lost soul.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#57
post #10

I wish there was a Rust-like programming language that was just a little bit higher level than Rust. I like Rust's wide ecosystem with high quality packages, the nice type system, traits, the idea that my code generally runs pretty fast even if I'm being lazy about writing good code, and my code usually working correctly if it compiles. I care about speed and correctness but Rust makes me also care about ownership an…

> I've looked at languages like Nim and read about research languages like Koka

Nim is indeed going in the right direction with ORC/ARC

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#58
post #8

I've been programming in Rust for the last few years. My daily work is mostly just fumbling through compiler errors until the code works. Some observations: - The compiler is always right. - Do what clippy and rust-analyzer says. Don't ask questions. - If you're fighting the compiler, clippy, AND rust-analyzer, then you're almost definitely wrong. Virgins try to use &str everywhere. Chads just use String.

This sounds like a terrible way to exist.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#59

Unpopular opinion: I find rust code unreadable. And I consider myself a polyglot. I am sure all those symbols have a special meaning but it's like perl to me. Just throw some random special characters and they all mean something.

It's unreadable until you learn the language. It is not something you can just look at and start writing/reading.

Also there aren't that many special symbols, it's not scala after all.

Spend two weeks with it and it makes sense why things are the way they are for the most part.

Re: Rust Is Hard, Or: The Misery of Mainstream Programming

#60

Rust does not have to be this hard. Most of the pain here come from the unholy trifactor: combining async, lifetimes and dynamic dispatch with trait object closures; which is indeed very awkward in practice. Async support is incredibly half-baked. It was released as an MVP, but that MVP has not improved notably in almost three years. There are lots of ideas, some progress on the fundamental language features required…

> Most of the pain here come from the unholy trifactor: combining async, lifetimes and dynamic dispatch with trait object closures; which is indeed very awkward in practice.

Even in regular Rust, trying to get too clever with lifetimes can cause serious pain. The usual culprit is complex code that tries to never allocate memory. "Oh, well this closure borrows this parameter from the parent function, and then stores a reference to it in this stack-based structure inside the closure, and then we pass everything by reference to this higher order function..." Just say no.

If you add async to the mix, then you need to keep your ownership simple. If you have a long-running async function, then pass parameters by value! If you have a polymorphic async function, then return your result in a Box. (This also breaks up the generated state machine used to implement async functions, and can reduce binary size.)

So much of this pain is caused by premature optimization.

In C++, if you get to clever, you eventually make a mistake and segfault. In Rust, if you get too clever, it eventually becomes impossible to satisfy the borrow checker. Most of the time, the solution is to be less clever.

Async Rust was a fascinating experiment, but in practice, I think it turned out to be a tool that's best used conservatively. I've written some very stable and high-performance production code using async Rust. But I keep it simple when I can.

Post reply on HN