For the vast majority of software you want a managed runtime.
Some of the problems Rust “solves” are problems you shouldn’t be having in the first place because we mostly write software that doesn’t need direct control over memory. Borrow checking isn’t something you want to have to deal with - it is something you have to accept when you have chosen to manage memory. That choice has a high cost that cost never gets paid off in most projects that could work just as fine with managed memory.
I’m a Go programmer, but this article reminded me that I should have more experience with Rust. From my perspective Rust seems a bit less practical. The standard library lacks support for cryptography, for instance. The compiler is slow, which is a productivity killer. Overall concurrency seems like a bit of an afterthought. Again.
What makes me want to try Rust in production are things like option types. Those would be nice to have in any language. Any issues that can be caught by the compiler are a plus. Getting rid of nil would also be a plus, but to be quite frank, I don’t experience that many nil pointer errors.
The author does nod to the static analysis tools for Go. Yes, they are not part of the compiler (for good reason), but they do a pretty good job in practice. So you get more than the compiler can promise at a fraction of the cost (measured in build time). That’s a much bigger deal for actual developers than we generally give it credit for.
Then there’s the stuff that makes me less convinced in terms of arguments. For instance the fact that Go didn’t have generics early on and that the standard library doesn’t use them. Generics were not as important as people thought they were. In practical reality. The fact that the standard library doesn’t make wide use of them is not a weakness, it shows restraint. They didn’t go overboard and prematurely plaster generics all over the place as soon as the language supported it. This is the kind of restraint you want to see. Remember how horrible Java was after everyone started abusing generics? A brief generation of software that was significantly worse, and less maintainable resulted from this exuberance. For the ultimate example of what happens when you give people every feature they wish for: look at C++. It´s not a very good language because it is many languages. Just because there are standards and recommendations doesn’t mean that all code magically gets rewritten to a narrower definition of the language. It means that we accumulate intermediate forms. I expect people who are interested in languages to understand these dynamics.
Rust's stdlib is small, Go took more of Python's "batteries included" strategy.
So in that sense it seems like a category error to try to look for crypto stuff in the standard library. Of course this brings the well known problem of "okay, but then which one should I use?". Nowadays this is largely solved by a few web searches and LLM queries, and people are quite helpful at https://old.reddit.com/r/rust/ .
Go was shaped by the needs of Google, Rust is a wildly successful amazing experiment in programming language and compiler design that really got out of hand :) (A bit like JavaScript! Or even C#! Or Python. Same growing pains (async/await!), but arguably on different levels.)
It turns out that the needs of Google overlaps significantly with the needs of software engineers outside Google. That argument could have been valid for a while after its initial release. But now it is just a lazy argument today.
I think batteries included is a better strategy. To the degree where I think Rust should reconsider this decision.
Rust likes to do things neat and proper and inclusive and community and zero-cost (or ALARA [as low as reasonably achievable]), and so on.
But there's no theory of standard library that they could implement. Shipping things together makes sense, but the maintenance burden is already significant, and there's also no theory of "ethically cloning open source maintainers".
I'm also quite squeamish when I think about all the unvetted dependencies, so yes, there's definitely a need, but I don't think slapping a stdlib tag on millions of lines of code would lead to great things.
But sure, I think someone could champion the case to introduce a process for adding projects to the standard packages. The projects would need to show some competence, commitment to quality and security. And the process obviously needs to have an orderly procedure for deprecation, and for "non maintainer updates" (like Debian has, for example).
It also means that everything is (over) optimised for Google's usecases, but not general purpose applications
I came across this problem pretty directly a couple of weeks ago - I wanted to see if I could port a small C program to Go, where one of the needs is to create gzip archives. But the Go stdlib insists on extraneous padding that breaks the backwards compatibility requirements of my program.
The padding isn't needed, it isn't useful, and you can't opt out of it. So the whole program went in the bin and I have resumed maintaining it in C
This is one of dozens of situations I've experienced where Go's allegedly pristine stdlib design has kicked me in the nuts
Somebody at Google decided this is how they wanted it to work. They don't have to explain why and they don't have to fix this deficiency until it becomes a problem for Google
It seems the problem here is that they didn’t “fix” whatever you thought was “broken” and you are upset. And somehow you extrapolated that to mean that Go only follows Google’s needs.
Be a bit more precise. What exactly are you talking about and and what do you think Go does wrong and why have they chosen to do it that way?
Rust has clearly opined that they prefer a small standard library and a "choose your own libraries" vs "batteries included" approach.
If Rust included a crypto lib and a vulnerability was discovered, many fixes are backwards incompatible. Rust maintains strict backwards compatibility, which means updating the relevant crypto functions in the std lib would necessitate a major version bump. By keeping crypto outside of std, it allows the community to make backwards incompatible changes at a higher pace.
Python handles backward incompatibility changes via multi-year deprecations. I'm not familiar with Golang but a quick Google search reveals that it deals with this by using feature flags via GODEBUG. Excessive feature flag use is a bad pattern in my experience years ago, but I don't know if that's applicable here.
I prefer the trade-offs of a "choose your own lib" approach, but I understand the advantages and preferences of those who prefer a "batteries included" approach.
In general, I get your argument, but cryptography is the perfect example for something so well-specified, well-understood, and extremely widely used, that these arguments do not really apply. You are not going to have to make backwards-incompatible changes to SHA256 or Poly1305, etc. It has minimal API surface too, and is not going to be a large maintenance burden. But nearly everybody is going to need crypto at some point. It is great to have blessed and well-audited standard implementations that people can rely on, without even having to make a choice. This it is not something where you want “the community to make backwards incompatible changes at a higher pace.”.
Crypto is something any modern language should include in the stdlib, imo.
Proviso: you do cryptography in the stdlib if you have the means to do it well. Go did; Filippo Valsorda has built a whole company practice on keeping that library excellent.
Certainly, that's a better outcome than just providing bindings to OpenSSL, which is what most other languages do.
I think I agree, but I am not sure I understand what "the means to do it well" actually means. I would think of it more as a community decision: let's focus efforts on doing X well in the standard library since X is important and people shouldn't have to ask "ok, so which third party library is the best choice right now".
Let me be the first to point out that this is not an easy thing to do since it depends heavily on the community/team/maintainer dynamics. Even agreeing on the goal or scope can be really hard. But if the Rust community is as good as people say it is, that should be doable, right?
On the other hand it wouldn't have to be definitive and exhaustive. Just a safe default. Like http muxers in Go: the one that came with the standard library was fine for a lot of uses, but people generally used third party muxers. I certainly did. And then one of the most used third party ones became shaky as it was no longer being maintained (now it is again, I think). Eventually the one in Go was improved to where I'd prefer to use that since it represents a "safe default" (and I am probably not going to need whatever extra features or performance third parties can provide).
Also note that I see myself first and foremost as an _engineer_. I care less about purity in theory than what things mean in practical terms. And in practical terms I appreciate Go for having so much useful stuff in the standard library. Stuff I kind of think we should take for granted in any serious language today.
Some of the problems Rust “solves” are problems you shouldn’t be having in the first place because we mostly write software that doesn’t need direct control over memory. Borrow checking isn’t something you want to have to deal with - it is something you have to accept when you have chosen to manage memory. That choice has a high cost that cost never gets paid off in most projects that could work just as fine with managed memory.
I’m a Go programmer, but this article reminded me that I should have more experience with Rust. From my perspective Rust seems a bit less practical. The standard library lacks support for cryptography, for instance. The compiler is slow, which is a productivity killer. Overall concurrency seems like a bit of an afterthought. Again.
What makes me want to try Rust in production are things like option types. Those would be nice to have in any language. Any issues that can be caught by the compiler are a plus. Getting rid of nil would also be a plus, but to be quite frank, I don’t experience that many nil pointer errors.
The author does nod to the static analysis tools for Go. Yes, they are not part of the compiler (for good reason), but they do a pretty good job in practice. So you get more than the compiler can promise at a fraction of the cost (measured in build time). That’s a much bigger deal for actual developers than we generally give it credit for.
Then there’s the stuff that makes me less convinced in terms of arguments. For instance the fact that Go didn’t have generics early on and that the standard library doesn’t use them. Generics were not as important as people thought they were. In practical reality. The fact that the standard library doesn’t make wide use of them is not a weakness, it shows restraint. They didn’t go overboard and prematurely plaster generics all over the place as soon as the language supported it. This is the kind of restraint you want to see. Remember how horrible Java was after everyone started abusing generics? A brief generation of software that was significantly worse, and less maintainable resulted from this exuberance. For the ultimate example of what happens when you give people every feature they wish for: look at C++. It´s not a very good language because it is many languages. Just because there are standards and recommendations doesn’t mean that all code magically gets rewritten to a narrower definition of the language. It means that we accumulate intermediate forms. I expect people who are interested in languages to understand these dynamics.