Live data from Hacker News

Rust Is Hard, Or: The Misery of Mainstream Programming

hirrolot.github.io

151–160 of 811 posts

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

#151
post #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…

> If you have a polymorphic async function, then return your result in a Box.

Agreed. Copy, Clone, Box, Arc, RwLock, etc. are your friends. Don't be afraid to use them.

You don't need as much performance as you think you do. Passing things around on the heap is fine for most applications. The Rust compiler is often smarter than you think.

And, when the Rust compiler is dumb or your code is getting stuck, you have code that you can understand and find the hotspot of. Now you can be clever.

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

#153
post #47

As someone that has only dabbled in Rust, the post reminds me of C++ and its mind-boggling templating system. Rust even seems to provide you with the multi-page compile errors. Is it really as bad, or does the post only highlight the misery you get when you're working on the fringes of what the language is capable of doing?

For me the notable difference is that the Rust compile errors are almost always about the problem I actually have. They can be quite verbose, but that's largely from showing me what the problem is exactly. e.g. Rustc will show you where you borrowed X and then where you tried to modify it after forgetting it was borrowed, not just go "You can't do that, it's already borrowed" and expect you to figure out where and ho…

To be fair, async (and generators, closures and Iterator) can expand to fairly hairy types with innocuous looking code. A think I do to simplify the output is to rely on `impl Trait` or `Box` to erase the type at strategic points, but that's working around my inability to find a way to make rustc figure out whether the full type is relevant or not right now.

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

#154

Async rust isn't pretty. If you are using async rust, and want to borrow data, use an Arc . In fact, if you ever use tokio::spawn, you will have to use Arc anyway because it requires 'static lifetime.

True about 'static. Sometimes I think I need an IDE shortcut for `Send + Sync + 'static`. Like `if err != nil`, you know :))

The trait_alias[1] nightly feature might be what you want :)

It was dormant for a long time, but it seems like it might be getting some love towards stabilization (or outright removal, I guess) at some point in the medium future.

[1]: https://doc.rust-lang.org/beta/unstable-book/language-featur...

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

#155

I've been doing async Rust since the tokio 0.x combinator days, and I remember being like OP. For some reason `Arc` did not exist in my mind and it was a struggle appeasing the borrow checker. The Go version is similar to the final Rust version; except the Go version is forcing you to use Arc everyone[1]. Seriously, just use Arc (or Arc >), in 70% of cases you are wrestling with the borrow checker trying to do someth…

I do completely agree with your advice of using `Arc`s. But unfortunately, sometimes it gets very tedious to deal with all these `Arc`s: https://github.com/teloxide/teloxide/blob/ec1d41220c51872cf9....

It also blurs the advantage of Rust as a lifetime validation tool if you use reference counting anyways. But it seems that it's the only viable approach for async at the moment.

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

#156
post #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…

> So much of this pain is caused by premature optimization.

Part of the problem is that Rust itself has such lofty aspirations to do it all (particularly "abstraction without overhead"), and is largely successful at that. So if I compromise on efficiency, it feels like my code is unworthy of the language it's written in.

Also, it's easy to feel that the slightest inefficiency puts us on a slippery slope to the bloat and slowness of something like Electron. I'd like to fight back against that bloat, the upgrade treadmill, and the rapid obsolescence that serves hardware makers but hurts poor people. On the one hand, there was good software in the 80s and 90s that made liberal use of heap-allocated, reference-counted objects with dynamic dispatch. On the other hand, there were slow, bloated desktop applications before the rise of Java, C#, Electron, etc. So I don't know where the right balance is at.

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

#159

Earlier quoted context omitted.

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, usu…

> 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. Enforcing correctness at compile time is not the only way to insure correctness. Some do enjoy solving language puzzles (so choose Rust) and some prefer thinking before coding and prefer solving design puzzles. I personally prefer that latter, as the 'hard'…

> Enforcing correctness at compile time is not the only way to insure correctness.

> some prefer thinking before coding and prefer solving design puzzles

Yeah, you just need to guarantee that person working on it, considered all edge cases, had uninterrupted time to think, thought about how the edge cases interact, didn't make a single mistake, wasn't sleepy, under influence of substances, and perfectly wrote it into the program without a single semantic error (off by 1).

Easy.

That's why I code in Malbolge Lisp CodeGen that outputs Brainfuck.

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

#160
post #140

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…

Rust is like C++ in the following way: it has many features and a complex type system, but that doesn't mean you should use all its features all the time! Dancing around with lifetimes can be premature optimization. Yes you can write very efficient code that way but if you find yourself spending tons of time fighting the borrow checker you might be overdoing it. I tend to use Arc a lot in async code. It makes things…

> Rust is like C++ in the following way: it has many features and a complex type system, but that doesn't mean you should use all its features all the time!

... Until third-party libraries push you to use specific features.

Post reply on HN