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.
Rust Is Hard, Or: The Misery of Mainstream Programming
31–40 of 811 posts
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#32I 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…
That said, they all don't give you what rust gives you and have their own troubles.
The truth is, either you care about life times and ownership, or you really don't care much about speed and correctness. Not saying that targeted at you as a person, but the royal "you". Even in c/c++ I have to think about that stuff, there's just no tools for it .
Fwiw you can import crates to have a gc in rust. To me it defeats the purpose. Wishing you the best on your search
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#33I 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…
Go and Hare are rust-adjacent with just a touch of crayon involved. I highly recommend both especially Go since you mention rust with GC
My only real issue with Go is that I feel the language part itself is simplistic and doesn't have the kind of type/trait/typeclass/similarthing like Rust or Haskell has. In Haskell I especially like doing DSLs using monads, e.g. I did a integer-problem-to-SAT-problem DSL and another DSL for NetHack playing AI. In Go making these DSLs is more pain. Although I think that would be true for Rust as well, just not as much.
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#34Rust 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…
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#35I 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…
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#36Earlier quoted context omitted.
I think that's ocaml. Higher level, with GC, nice type system, no traits but signatures and higher order modules might be enough for you, and a compiler that produces fast native binaries.
I think you are pretty spot on here. I write Rust and Haskell most of the time, where the choice depends on the kind of project I'm working on. Also I've written Rust professionally but Haskell has been confined to random hobby projects. I love Haskell but it has its own flavor of problems. I've meant to brush up a bit on OCaml; I've heard it has interesting features in its module system that Haskell does not have (m…
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#37I 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…
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#38Rust 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…
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…
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?
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#39Rust 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…
This should be more ergonomic as this should get rid of everything needing to have send/sync traits. I also suspect it may be more performant as I am not sure how good the async runtimes are about keeping scopes pinned to a particular core so its not constantly jumping around and busting the l1 caches (which would be extremely detrimental to compute latency and bandwidth)... Happy to be schooled on any of this.
Re: Rust Is Hard, Or: The Misery of Mainstream Programming
#40But Rust is a really bad general-purpose language. Because Rust isn’t a general-purpose language. It’s designed for high-performance, low-memory, safe computing. The only reason it’s even remotely considered “general-purpose” is because of how great it is. Unless you actually need to write something that’s high-performance, low-memory, or safe (or there’s a really important package in Rust that you can’t find anywhere else), stick to something like Swift or Kotlin or Java or TypeScript. Or even JavaScript or Python or Lua if you’re only writing small scripts.
-
Rust abstracts almost nothing about the OS. In order to understand Rust, you need to understand at a low-level how computers actually work and how languages compile. You need to understand the what, why, and how of threads, the stack / heap, I/O, endianness, etc.; and language features dynamic dispatch, references, async runtime, memory management etc.. These language features are all implemented in Rust, but they’re explicit, you have to think about them and choose your implementation.
People say that Rust is hard because of the borrow checker but there’s much more than that: dyn Traits (you have to understand when a trait can and cannot be dyn), Unsized types (and why there are so many type parameters, because everything must be sized), closure traits, multi-threaded communication, what async actually does, etc. Heck, we almost got you to manually choose allocation schemes (they’re default type parameters, which is weird because Rust doesn’t have many implicit defaults).
You often face decisions like
- should this trait be a static / type parameter, or dynamic / Box?
- Is this value borrowed or owned or Cow?
- Should this be a unique reference / Box or a shared reference / Rc or a shared-across-threads Arc or not a reference at all?
- How do we control this value and communicate across threads, do we make the whole thing thread-safe or message passing or provide a shared Mutex/AtomicBool?
- How do we manage async, do we set up an async runtime ourselves (and if so how do we configure this runtime), or how do we add integration with existing async runtimes?
- Should this be a Cell / RefCell because we don’t want to or can’t pass a single mutable reference around? And when / how do we dereference the RefCell as to ensure it doesn’t get accessed anywhere else until the dereference is dropped?
- Can we do this safely, aka encode it in a way the compiler understands? And if not, how do we a) do it correctly unsafe and b) make the unsafe code as short as possible?
-
And this explicitness is part of what makes Rust so amazing, because other languages make these decisions for you. But every decision has costs, and either they a) incur higher overhead, or b) lose safety guarantees.
e.g. in JavaScript everything is on one thread, so no data-races but no true parallelism; everything is garbage collected, so no use-after-free or double-free but you get GC spikes; everything is a dynamic boxed reference and types are checked at runtime, so no passing complex types and type parameters everywhere, but calls are much slower and there is no true type-safety.
Or in C++, there are multiple threads with shared memory but you must explicitly avoid data-races; there is no GC overhead but you must explicitly manage allocs/frees; you can choose whether to pass/store things as references or values and there’s a type system, but values can be assigned / casted to the wrong types leading to memory corruption.
Rust is the only mainstream language where you can do unsafe-but-efficient stuff, but it’s actually safe because it’s checked at compile-time.
-
But this explicitness also makes Rust a bad general-purpose language. e.g.
If you want, you can pretty much make everything in Rust like this. #[tokio::main] for the implicit async runtime, everything Gc> for no borrowing concerns, dyn Any with upcasting / down casting, etc. This is mainly at the cost of a ton of extra syntax. And of course you get higher overhead and lose compile-time guarantees, which are now checked at runtime.
Or better yet, what you should actually do, is write your code which doesn’t need high performance, low memory, or security guarantees in another language. And possibly interface it to Rust code with FFI.
Because Rust isn’t a general purpose language. It tries to be general-purpose, and is to an extent, but it’s ultimately built for niche performance and reliability guarantees, and you just can’t have those without user overhead.