Feedback on Rust Programming Language / std

I am sorry when something is incorrect.
Then please correct it. Thank you.

Here my feedback:

I wanted to start a project in Rust. But ChatGPT says Rusts std does not have json support.
Now I am a bit I disappointed and thrown back into reality.

I do not want external dependencies for basic building blocks.

Then constructive part of the feedback:
Have a standard library that supports basic building blocks.

Regarding [1] "Too much crate dependencies for relatively simple tasks. I really think there should be "official rust" crates for these."

I would extend this with just comes with Rust std.

I am doing a lot in Node.js. The std is not complicated but huge. For me it feels very close to system level, because you can start a process and then have the data streams. As one example.

Now I wanted to switch to Rust for performance. I can't get used to it to switch from npm package hell to create deps. See [1]. I thought the Rust std is well sorted. So onboarding is easy.
I can not get my head around the fact that why I wanted to install something from the internet.
And yes, I probably would have written leftPad myself instead of installing it. So I thought when switching to Rust the std has everything prepared for me.

Idea for improvement:

extend the std with more building blocks. It does not must be perfect. A std can always evolve and why not have multiple implementations for json.

std: standard library
[1] I stopped with rust

TLDR: npm is pretty bad, sure, but cargo is a lot better. Give it a try for a while, you might find you're pleasantly surprised. If not, then at least you will have more specific complaints than "it's bad in this other language"

There's a good reason Rust doesn't put a lot of "basic building blocks" in the standard library. It often turns out that they aren't actually that basic.

serde, the most popular deserializer library, is a surprisingly complicated and evolving ecosystem, after all json isn't even directly supported, that's in serde_json, and it has serious competing approaches including fresh approaches like facet

Putting things in the standard library means they are forever due to backwards compatibility, you can't improve them, you can't change them.

18 Likes

Many good solutions are missed in std, as for me: json, regex, http client, zip, ssl socket... Anyway I've implemented most of them myself and forgot the problem. Even Kernighan noticed weakness of Rust:

Speaking of Rust, Kernighan said “The support mechanism that went with it — this notion of crates and barrels and things like that — was just incomprehensibly big and slow.”

“And the compiler was slow, the code that came out was slow…”

I guess his problem was that he used Cargo, otherwise he could say that Rust compiler is a very fast. Most of my compilations take a sub-second.

I also just watched that video, and he's quite clear that he barely touched Rust. I can only imagine the reason the "code that came out was slow" was because he didn't use --release, for example: it's been shown many times that Rust generates nearly identical code to C, on average. His actual complaints are basically just that it's something he's not used to: "lifetimes when I'm not even dealing with allocation" for example, when dangling pointers have nothing to do with heap allocation (one assumes he allocated some local variables at least)

(The question is at about 1:02:30 in this video, if those following along at home want the full context; be warned he's playing to a very Rust-hostile audience, he might be a bit more even-handed in another context)


Cargo does little to nothing about the speed of the compilation, but using third party packages that have a lot of code does affect how much code you compile. Further, many of the designs that make it easy to use a library, that you're unlikely to use for your own benefit, can have poor effects on compilation time. There's also the fact that generally it's so hard to use libraries from source in C that nearly everyone that does use a library expects you to have them installed already, and it's your problem to make sure the versions match etc., so of course you're not paying to build those too.

As you have found, Rust isn't that much worse than C when you're careful with how much code you touch, and how it's written: not nearly as fast for a slew of reasons, but perfectly usable. It's just a pity that the default is so strongly in favor of slow compile times.


Edit: fixed the timestamp! Thanks @mroth

1 Like

Rust is a programming language with different targets than JavaScript.

For example, embedded devices with just a handful of megabytes of memory and storage. In such devices, using something like NodeJs is impossible since just the runtime already occupies tens of megabytes in memory.

This is one of the many reasons why Rust's standard library needs to be minimal. In some extreme cases, even the standard library is not minimal enough and people need to opt-out from it with the so-called no-std.

And Kernighan also said ""I have written only one Rust program, so you should take all of this with a giant grain of salt,".

I could not fathom how Kernighan said he "could not grok the mechanisms that were required to do memory safety, in a program where memory wasn't even an issue!". I mean they are the same mechanisms you need to ensure memory safety in C, except they are enforced by the compiler not the programmer.

2 Likes

I for one am very happy that the Rust std library does not come with everything including the kitchen sink. In the same way that C doesn't.

7 Likes

It is at about 1:02:30: (direct link: https://youtu.be/WEb_YL1K1Qg?t=3750)

1 Like

(Just a thought, so maybe completely off the mark of what Brian Kernighan was thinking.)
If you have the mindset of safety is something you must do (e.g. check malloc return value.) you might fail to grasp that your not responsible for such check when using rust. Until you head out of the standard, but staying away from unsafe is encouraged. Rust-safe also having a very confined meaning also is an extra thing to learn.

Checking the return value of malloc is almost entirely useless.

Typically on Linux (and likely Windows) malloc will overcommit. That is to say if you ask for some memory it will happily return OK even if there is not enough RAM available. Thanks to the use of virtual memory you don't find out there is no RAM for you until you try to write to it. At which point the virtual memory system will try to map some free pages for you and fail with some kind of TRAP if it has none. That's assuming the Out Of Memory detection system has not killed you off for being too greedy already :slight_smile:

2 Likes

Nah on Windows as far as I know you will actually get null, but you basically never get there because Windows default enables a (now) gargantuan page file.

2 Likes

Thanks for sharing your thoughts, @manuel.

If you wouldn’t mind considering some feedback on your own approach in the matter that has led to this discussion in the first place, here are just a few points that came to mind right away.

Starting a project in Rust, and explicitly confining yourself to the std alone, simply because “installing something from the internet” giving you a bad “vibe check”; are two different matters.

Researching/contrasting/comparing the pros/cons of a higher-level, interpreted runtime environment (Node), with the dis/advantages of a compiled language (C/C++/Rust) would have most likely giving you a slightly better overview of the “reality” you are now disappointed by.

As long as we stay firmly planted in the realm of “reality” still: it is worth recognizing that there are no universal “basic” building blocks out there. Only blocks any one individual might think of as “basic”, due to the amount of exposure they’ve personally had with a particular side of things.

Your own familiarity with js/npm/node: the last of which is powered by V8, itself conceived primarily for the browser-centric workloads; does not comprise the most universal experience out there, either. There is a reason a “JSON Object Notation” is named the way it does. There is a reason why any JS runtime environment would be outright foolish not to provide any decent support for it.

There is no obvious reason why a language that is meant to power both microcontrollers and servers under the highest of loads out there should adopt the same of reference as that of the team behind Node and its standard library, on the other hand. Different strokes for different folks.

Yet another thing about this “reality” we can’t seem to get enough of. It doesn’t run off adjectives. “Well sorted” is a matter of personal opinion. Same goes for whether any given “onboarding” process happens to be (or feel, if we’re perfectly honest with our wording) “easy” or not.

Particularly so, when any matter of engineering is concerned. Software engineering, as well. If “performance” is your actual goal, figure out which other side of the equation has to give way to it. If merely getting familiar with the ways and quirks of an entirely different language feels like an insurmountable exercise, however - including the need to cargo add a few dependencies - stick to JS/TS. Clearly, it’s what you know and like the most. Why even bother looking elsewhere?

This feels like the main crux of the issue. If the Node alone “feels” close enough to a system level, you don’t need anything with even remotely as steep of a learning curve is Rust. Around these parts, “system level” means being able to throw a bunch of bytes into an array, copy it into an executable region of memory, then call the pointer to that memory as if it was a fn(A) → B.

Vastly different strokes, for vastly different folks.

Try giving it a shot if you ever feel like stepping down a few abstraction layers into the nitty gritty parts that your hardware and OS deals with. As long as your goal remains “give me Node/JS but more performance” you’re going to have an absolutely miserable time with this particular lang.


For reference and proper expectation management:

8 Likes

I do wonder what you mean by that.

All my long life "systems programming" was writing the code that is going to be "the system". Be that operating system, embedded system, language system, database system, memory allocators, etc, etc. It's all about writing OS kernels, file systems, graphics systems, device drivers, compilers etc, etc.

In the case of node.js the "system" you are using is the V8 Javascript run time, written in C++, sitting on top of the Linux OS, written in C. From what you have said you are far away from that.

Indeed things can evolve. Including standards. The problem is when a new implementation of something arrives with better performance or API or whatever, if it's in the standard library then the standard library maintainers have to maintain the old incarnations for ever. This does not seem like a great idea to me.

A classic example is the C standard library, full of really bad functions, many of which it is wise not to use. But C has to carry those around forever because they are "the standard".

1 Like

Sure, Rust can be used for writing very simple programs. In this case, Rust memory safety is certainly overhead. So, benefits of Rust start working when a code is complex enough that a developer can't control all cases easily.

1 Like

It's one case I hate in Java. Std there may have too many implementation and it isn't easy to handle all of them. An interesting thing that even Java having many implementations is trying to end with only one internally.

Eh, exactly the case where you can fit all the lifetimes of values in your head correctly is the cases where the lifetime checking doesn't get in your way at all - once you've actually used it enough to know why it exists and how it works.

It's the more complex ones where, after a lot of careful thought you're pretty sure that what your trying to do is actually safe that the lifetime checking actually becomes a problem. That's when you have to consider either adding a bunch of ugly warts to keep the checker happy, or try to figure out a clever redesign that is probably even more work, or add just a little unsafe, just a taste, it'll be fine this time. Getting good at rust is basically at least half being able to predict and avoid the above.

I wonder what you mean by that. For example I can write very short and simple code in C or C++ that violates memory safety. For example a function returning a pointer to a local variable or a C++ function that refers to an element of a vector and then invalidates that by pushing to the Vector. I would claim that the Rust memory safety checks are useful there and not "overhead".

You are right of course, the bigger the code base that harder it becomes for the programmer to keep track of memory safety in his head and the more valuable Rust becomes.

5 Likes

I started a big AI project in Physics couple months ago. Certainly, I had to select a programming language for its implementation. You know how I like Rust, however I selected Java. Using C++ or Rust was a stupid decision in my opinion. Why? Returning a pointer to a local variable is certainly a problem, but when you use Java, it won't stop you from delivering code. if you use Rust, then you need constantly think how to avoid certain memory safety problems. My programmers have the expertise in AI, but not much in memory safety. Why should I waste their and my time on that? Time is money.

When I learned Java, there was a slogan - "compile once, run everywhere" It worked until version 8. When I learned Rust, there was a slogan - "if you can compile, it will work". I wrote the following code last Friday:

let append = redirect == ">>";
let mut file = OpenOptions::new()
                                    .append(append) 
                                    .create(true) 
                                    .open(file)?; 

It was compiled fine. However when I ran the program, I got a crash with a message - invalid argument. What??? Everything looked decent. I switched to Raspberry Pi and updated rustc to 1.91 nightly. Now, I got a little more explanation - a file need to be opened either for write, or append. So, see, Rust is far not perfect.

That's an API-design problem, not a language-design problem.

It's still interesting though, I wonder if fixing this kind of API-design issues can be done on the standard library :thinking:.

3 Likes