4 ms·
As a longtime embedded C developer (20 years) I always look forward to truly learn Rust someday. But unfortunately I don't have much time now to learn it. And I
by scoutt 5y ago
As a longtime embedded C developer (20 years) I always look forward to truly learn Rust someday. But unfortunately I don't have much time now to learn it. And I'm in a kind-of hate-love relationship with Rust at the moment. The same applies to modern C++.
> many people report a sense of high "cognitive overhead" in using it, and "learning curve" remains the most common reason not to use Rust
This is me.
And I was super excited when I read "we will identify and eliminate many of those patterns and idiosyncracies".
Then... the post follows with "extend the language", "Extend our async-await support", "Broaden the set of traits", and I know what this means. More things to learn, more time to reach an operative state.
And this kicks in: https://en.wikipedia.org/wiki/Overchoice https://en.wikipedia.org/wiki/Overchoice
Someone should invent RISR (Reduced Instructions Set Rust).
- pornel 5y agoDon't get discouraged by this. The features being added may sound academic and obscure, but they make the language simpler to use. This pattern has already been repeated a few times: Before: "Uuugh, I want to do X, but the compiler says I can't! Why can't I do this simple thing!??" After: It works. For example, Rust used to have an embarrassing problem with cloning arrays larger than 32 elements, for silly obscure reasons. Since then it has added a "const generics" feature, and cloning and iteration over arrays works just as you'd expect it to always work. The current issue is that traits (which are a bit like interfaces in Java) don't quite support async functions, for silly obscure reasons. Currently if you want to have an interface that is both abstract and async, you need to manually implement workarounds that add complexity and overhead. Rust is removing this problem by adding language-level plumbing that was preventing it from having traits just work for any type of function. Rust's evolution isn't adding bells and whistles, but filling in holes.
- scoutt 5y agoThis is the perfect example. For instance, I don't need Traits or Async or generics for embedded. I can pass a struct into functions as I've been doing my whole life. Async is not supported (but I can generate my own interrupt-driven state machines). In C I don't have an "abstract and async traits interface". I wouldn't even imagine why I need one "in the language". Do I need one? Does a bluetooth stack or kernel driver need one? I can make a struct with pointers to functions, and there you have an "interface", done with the basic elements the language provides. I undertand that these features are a "nice-to-have plus", but what all these updates actually generate in a system/embedded developer like me is fatigue, and not only at cognitive level but also "I've changed compiler version and I have to revalidate all over again". Why? some purple-haired 25 years old across the ocean needed an "abstract and async traits interface". Now the bread on my family table depends on what they've changed. I imagine that perhaps Rust tries to make everyone happy, but here are my two cents from my PoV.
- pornel 5y agoRust doesn't cater to small (short) programs, which some embedded programs may be. It's been originally envisioned for making a modern browser engine, which is almost an entire OS these days, so many of its features start making sense only when you need to work with programs big enough that you can't fit them all in your head at once, and have to maintain for a long time, cooperate with other developers, deal with 3rd party code, etc. Features that are layers of abstraction are hard to explain on their own, so I don't think I can justify them in just a HN comment. I remember when I have been reading about Encapsulation in OOP for the first time, and I completely didn't get it — why would I hide struct fields from myself!? I know they're there! Rust's traits are such an abstract feature that doesn't directly translate to things that CPU does, but it's a building block for a few higher-level language features: • Traits can be used like a Base Class or Interface in OOP, so for example you can make structs "Serializable" and have a data format writer know how to dump them to disk (assuming you need something smarter than fwrite(&struct) due to pointers or portability). Instead of having a one-off function for serializing your particular state, you can make each struct describe itself and "just work" when combined with a JSON/Msgpack/binary serializer. Rust makes good use of this for https://serde.rs https://serde.rs that is pretty nice to use and surprisingly efficient. • Traits can be used with static dispatch and combined with other types at compile time ("Generics" in Rust jargon). It makes them replace many things you'd do with horrible C macro hacks, and you get usually nicer syntax and type checking. For example, you can use containers (hash maps, btree maps) without void* cost and casts, and without include macro hacks. Linear search and linked lists can get you far, but when you need a better container, it's really nice to have best-in-class one available, and as fast as if you handcrafted it yourself. • If you prefer the struct-of-function-pointers approach, Traits can do dynamic dispatch that too ("dyn Trait" in Rust jargon). • Traits are nice to coordinate APIs across libraries. For example in C if you want to stream a file from a network, decompress it on the fly, and decode JSON, you need to write a bunch of glue code, because every library handles buffers slightly differently. In Rust there's io::Read trait, and people agreed to use it, so `json_decode(ungzip(request(addr)))` works, and it's streaming (functions here don't return malloced char*, they return sockets/handles that implement a trait that describes how to get more bytes from them). Sort of like a file descriptor, but using general-purpose feature, and it can also be integrated at compile time, so everything is as inlined and optimized as bespoke code.
- GolDDranks 5y agoRISR – Rust 1.0 was that language. It was already a significant reduction over some other languages: having no GC makes the language simpler implementation-wise than 95% of modern languages. Memory safety is then brought back in by ownership and lifetimes, but those _restrict_ what you can do, not the other way. In a way, Rust 1.0 felt like a minimal design that achieved the goals: great performance and low-level control with memory safety without GC. (Okay, there were some stuff around traits and type inference that were not _strictly_ necessary, I guess.) However, it was _not_ nice to use. Even with current Rust, which is a whole lot more ergonomic, there are many places that feel unnecessarily restrictive. Patterns that feel like they should work, yet they don't. Do you have any better idea how to make this stuff better without extending the language? Or maybe "worse is better", in which case Rust is not for you? Maybe you are looking after Zig? https://ziglang.org/ https://ziglang.org/
- scoutt 5y ago> "worse is better" Of course not! If I have to choose, regarding system/embedded programming languages, then I'd go with "less is better". > Maybe you are looking after Zig? Definitely Zig is under my radar too. Fortunately, after all, I'm not alone. Many others I hear from the industry feel the same way.
- varajelle 5y agoNew features is not incompatible with easier to learn. User will have to learn at some point how to do X with the language. Without the new feature, that might be some complex pattern which is difficult for user to remember, let alone come up with by themselves. While using an additional feature it may be trivial to learn that feature to do X.