I have been seeing hatred on this forum towards Rust since long time. Initially it didn't make any kind of sense. Only after actually trying to learn it did I understand the backlash.
It actually is so difficult, that most people might never be able to be proficient in it. Even if they tried. Especially coming from the world of memory managed languages. This creates push back against any and every use, promotion of Rust. The unknown fear seem to be that they will be left behind if it takes off.
I completed my battles with Rust. I don't even use it anymore (because of lack of opportunities). But I love Rust. It is here to stay and expand. Thanks to the LLMs and the demand for verifiability.
I find Rust much easier to write than C. Its types let me be reasonably sure I’ve written appropriate code before I even get to the point of running tests, and I don’t have to memorize the flow of the whole program to have that assurance.
12 | hover(altitude2);
| ----- ^^^^^^^^^ expected `Meters`, found `Feet`
| |
| arguments to this function are incorrect
Guaranteeing that I’ve never mixed units means I don’t have to worry about parking my spacecraft at 1/3 the expected altitude. Now I can concentrate on the rest of the logic. The language has my back on the types so I never have to waste brain cycles on the bookkeeping parts.
That’s one example. It’s not unique to Rust by a long shot. But it’s still a vast improvement over C, where that same signed 32 bit data type is the number of eggs in a basket, the offset of bytes into a struct, the index of an array, a UTF-8 code point, or whatever else.
This really shows up at refactoring time. Move some Rust code around and it’ll loudly let you know exactly what you need to fix before it’s ready. C? Not so much.
```
error: passing 'Feet' to parameter of incompatible type 'Meters'
20 | hover(altitude2);
```
Coming from a dynamically typed language (Python, etc), this might seem like a revelation, but its old news since the dawn of programming computers. A C language server will pick this up before compile time, just like `rust-analyzer` does: `argument of type "Feet" is incompatible with parameter of type "Meters"`.
Did you not know this? I feel like a lot of people on message boards criticizing C don't know that this would fail to compile and the IDE would tell you in advance...
> An investigation attributed the failure to a measurement mismatch between two measurement systems: SI units (metric) by NASA and US customary units by spacecraft builder Lockheed Martin.[3]
That was only the proximate cause, the ultimate cause was cultural. As complex systems and efforts run into problems, it is trivial to blame the unit conversion when they had been ignoring people for months who had concerns [0]
> ... ground controllers ignored a string of indications that something was seriously wrong with the craft's trajectory, over a period of weeks if not months. But managers demanded that worriers and doubters "prove something was wrong," even though classic and fundamental principles of mission safety should have demanded that they themselves, in the presence of significant doubts, properly "prove all is right" with the flight
Dropping units on the NASA side also was problematic but really culture was the cause of the actual crash.
That's technically true, but if NASA's API accepted arguments in Meters instead of int32_t (or whatever the equivalent was in the language they used), then it would've been instantly obvious that the controller code that Lockheed Martin wrote was using the wrong datatype.
Do we know how the code was called, was it linked in or was it via IPC (the latter seems most likely to me, and then the question is does the IPC framework support a rich type system)?
That was exactly what I was thinking of when I wrote that.
But also think of how many libc functions take multiple ints or multiple chars in various orders. You can get carried away with typing, i.e. by having a separate type for everything*. Still, imagine you’re writing, say, a hypothetical IDE device driver and had separate types for BlockNumber and ByteInBlock so that it’s impossible to transpose read(byte_offset,block) instead of read(block,byte_offset), even if those are really the same kind of numbers.
That kind of thing makes a gazillion bugs just vanish into the ether.
I sometimes think about a related issue: suppose you have a function whose n parameters have n different types. Should the programmer be required to provide those parameters in a specific order? There's no ambiguity.
There appears to be some tension between different conveniences you might afford yourself. If you have read(offset: offsetTypeForRead, address: addressTypeForRead), you can catch when someone accidentally passes an address where the offset should be and an offset where the address should be.
Or, you can say "hey, I'm always adding the offset to the address; it doesn't matter which one gets passed first" and relieve the programmer of needing to know the order in which two semantically distinct variables get passed to `read`.
But if you do provide that convenience -- and it's not unintuitive at all; there really is only one valid interpretation of a combination of an address and an offset, regardless of the order you mention them in -- you lose some of the safety that you wanted from the types. If your variables are declared correctly, everything is fine. If there's a mistake in declaring them, you'll wave through incorrect calls to `read` that would have been caught before.
Huh, that’s an interesting point, and I’d have to think on that. There are still plenty of cases where ordering would matter, like subtract(a,b), unless you go whole hog and define that like
fn sub(a:LeftOp, b:RightOp)
but that seems redundant. There are still plenty of other cases where I could your idea being useful. Like I always forget whether (in Python) it’s json.dump(file, data) or dump(data, file). Ultimately, should it matter? I’m passing a file handle and an object, and it’s unambiguous how those two args relate to the task at hand.
How does this scheme of yours work with m/s and seconds.
IIUC, rust would NOT let you do a type checked m/s * s => m, so using the type system for these kinds of games is silly and dangerous (I presume you would have to do the dumb thing and typeconvert to the same type -- e.g.
(m) (speed * ((m/s) seconds))
to do multiplication which means you're inserting unscientific and reader-confusing type conversions all over the place)
That's no problem in Rust. You can have a Speed type and a Time type, and define the multiplication operator over them to return a Length value. In fact, there's already a library which does exactly that, with tons of predefined SI units: https://docs.rs/uom/latest/uom/
Related library Sguaba [1] from Helsing AI written by Jon Gjengset it allows you to define coordinate systems on the type level and safe conversion and calculation with them.
I love that sort of thing. It so much easier to get up and running with plausible results when it’s all but impossible to misuse the API. “Darn it, it’s making me cast Celsius to Meters before I call this function. Hey, wait, that can’t be right…”
I'm very confused, explain how this is not the case with C?
I haven't written rust, but my impression is the benefit is more about deeper introspection of things like lifetime than basic typesafety, which already exists in C/C++ (and is likewise occasionally bypassed for convenience, so I wonder how often the same is done for Rust)
Nah, you’re just not good enough. I for example would have never made that mistake when calling hover(int32_t) in C. And on the off chance I did, my reviewers would have caught such a simple mistake because they too are excellent C developers.
> Especially coming from the world of memory managed languages.
If people from that world complain about Rust, I surely wouldn't want them around a C codebase.
There's nothing wrong about memory-managed languages, if you don't need to care about memory. But being unfamiliar with memory and complaining about the thing that help you avoid shooting your foot isn't something that inspires trust.
The hardship associated with learning rust isn't going to go away if they do C instead. What's going to happen instead is that bugged code will be written, and they will learn to associate the hardship with the underlying problem: managing memory.
The problem here is that C is too basic, dated, with inadequate higher-level abstractions, which makes writing robust and secure software extra difficult and laborious. "Learning underlying hardware" doesn't solve that at all.
Debian supports dozens of architectures, so it needs to abstract away architecture-specific details.
Rust gives you as much control as C for optimizing software, but at the same time neither Rust nor C really expose actual underlying hardware (on purpose). They target an abstract machine with Undefined Behaviors that don't behave like the hardware. Their optimisers will stab you in the back if you assume you can just do what the hardware does. And even if you could write directly for every logic gate in your hardware, that still wouldn't help with the fragility and tedium of writing secure parsers and correct package validation logic.
Assuming you're right about the language being too hard for most people, the outcome I'd expect given the history of computing is that the language will fail or be stuck in a niche
Time and time again, theoretically worse solutions that are easily accessible win
I have been seeing hatred on this forum towards Rust since long time. Initially it didn't make any kind of sense. Only after actually trying to learn it did I understand the backlash.
It actually is so difficult, that most people might never be able to be proficient in it. Even if they tried. Especially coming from the world of memory managed languages. This creates push back against any and every use, promotion of Rust. The unknown fear seem to be that they will be left behind if it takes off.
I completed my battles with Rust. I don't even use it anymore (because of lack of opportunities). But I love Rust. It is here to stay and expand. Thanks to the LLMs and the demand for verifiability.