Rust in 2022
ncameron.org
ncameron.org
My other big beef with Rust is its lack of a comprehensive stdlib, unlike Go. Having to pull in tons of external crates of varying quality and with varying degrees of dependency chains is not particularly pleasant.
Having a decent, well maintained, stdlib that contains "the basics" that one would expect in any 21st century programming language is sorely missing from Rust, and from my personal perspective is something that would draw me back to Rust for another go at learning it.
What would you like to see in that? Genuinely curious, I've considered putting something together that's just a meta-crate that pulls in some others.
If I had infinite time on my hands it would be a fun exercise to try to improve on it.
Searching "Http request in rust" for me yields the the rust cookbook on the first result, which is using reqwest! (https://rust-lang-nursery.github.io/rust-cookbook/web/client...)
Regardless I agree that crates.io could have some more features but I am not sure how useful I would find a recommendation engine.
Requests is currently #6 in its Web programming > HTTP client category[0]. The download counts, number of contributors, version history, and dependent crates is also prominently displayed.
I see someone else has got there before me and my answer would not be dissimilar.
Stuff to be able to talk to web services (because let's face it, any modern software will be doing that) is the obvious low hanging fruit, i.e. HTTP, JSON, Crypto etc.
Beyond that (if its not there already) basic tools to enable out-of-the-box CLI writing (e.g. flags etc.)
The problem with adding this is that in 10-20 years it's not so useful anymore. Then you'd have:
* an outdated HTTP library (look at how "everyone" is using a 3rd party HTTP library in python)
* a JSON library no one uses (everyone used XML, now it's out of fashion. And JSON has obvious problems!)
* Old cryptographic standards that you'd rather not use
Perfect reason for not writing any software. None would work for 20 years without maintenance (there are some exceptions of course).
There are so many different idiomatic ways to instantiate a type in rust that a crate with a common calling convention for most data structures would be very useful.
It would be great to have a unified interface that exposes a common set of instantiation mechanisms and apis. Other lib authors should be able to implement this api and get the same calling conventions.
Indeed. I would almost put my neck above the parapet and say that in the 21st century any programming language worthy of its name should come with decent crypto out of the box.
Crypto is no longer an option these days.
Most of your points are related to documentation, and a bit patronizing.
For all I care most of the functionality is there, fast and reasonably well designed.
Some other candidates include: logging, anync runtime (Tokyo), random generator, regex
In fact, there are people (like me) who are very happily pushing back on moving stuff into the standard library unless it's clear that the code there can live for 30 years. And I do not see this for almost all the things you just mentioned.
I think many of us are feeling these days that the rust standard library might already be too large and it's better to be very conservative adding stuff there or only after an extended period of time of independent vetting. I have yet to not experience that standard libraries turn into very stale and outdated things relatively quickly that carries an enormous maintenance burden.
Even the Go standard library is quickly aging as contexts were not around when it was first created. It will be interesting to see how Go's standard library is going to evolve with Generics and more reliance on contexts.
If anything, I found go stdlib to age like fine wine. It doesn't do everything under the sun, but what it does it does very well and can easily be extended if needed.
I agree that we need a serious refactoring of Python's stdlib.
My hands start to sweat at the idea of this becoming The Python 4 Debacle.
There is no need to make Rust like Go, Go is already a great Go.
Philosophical reasoning like "Rust should have small stdlib" is horseshit. Ideal language has every function perfectly designed in the stdlib (kinda like PHP in 2003, lol). But to get closer to that dream you need some sustainable organization that maintains and expands that stdlib, wishes to do so and has resources to do that continuously.
If it's just random 5 people doing maintenance and hacking at their spare time, that's not enough for an expanding library of diverse code. That could be enough only for keeping very core features working/improving like const generics and borrow checker.
That way of thinking only makes sense if nothing ever changes. You even bring PHP as a good example here of how this fails fast. The world has changed greatly since 2003. The Python standard library carries three XML implementations and an outdated HTML parser irrelevant for the modern world. These libraries were state of the art when they were written, but it's the world around it that changed.
Now one can make the argument: why was it not modernized and updated? The simple answer is that people started building code against this and now depend on it working this way. The only way would be to completely rewrite them with new APIs, remove stuff no longer needed but then you're effectively back to just using crates.io and the likes. Except it's worse now because the standard library is a monolith and does not compose.
I agree you don't want everything in the stdlib, but havinga stdlib way to achieve something is pretty valuable, even if it's not the best way and never was.
In cases where libraries don’t keep up with changes in standards or whatever, yeah, you’re going to have to find another library. This is a part of our job that is pretty much unavoidable no matter the language. We should learn lessons like sticking dependencies you’re not certain about behind an interface to minimize the cost of switching if possible.
JSON library updates are a constant tedious chore for many in the Java world. Jackson and Gson have both had several we've needed to make over the years. Now, _most_ of these are due to non-default features where you allow it to deserialize arbitrary types that we don't use. But clients big enough to insist on a BOM and internal security teams both just see "Jackson version x.y.z has a RCE on it, you need to update", even if it's literally impossible to trigger without changing the application code to enable insecure features.
On the other hand, something like a json parser needing to change all the time to support the ecosystem is another good reason to keep it out of the stdlib, IMO. There are limited hands to work on Rust itself, and I’d rather they spend their time making improvements to the core of the language, stabilizing features, and so on. As a user of rust, I’m willing to pay the cost of finding a good json library if it means I don’t need to update rust versions just to deal with some issue in JSON parsing.
The thing is it’s easy to be wrong if you’re trying to predict up front what is going to wind up being stable and low maintenance and what isn’t, so the precautionary nature of what gets into the stdlib I think reflects that.
Turns out, they upgraded JSON.NET and it started to name fields in different case. Golang parser didn't really care about snake_case, camelCase or PascalCase but whatever parser we were using in Scala at the time actually did.
[1]: https://twitter.com/steveklabnik/status/1367854800193413126
Now there are reasons many people choose not to use the built in C++ std::map, and very nearly this ended up the case for Rust's HashMap, until they switched the implementation to the crate that was becoming popular. But even there's design decisions, like Rust using more compute to have a strong hash to avoid DoS attacks, that some may feel are inappropriate for their use cases.
Let's face it, what will your average dev do in the absence of something being in stdlib ?
They will (semi)randomly pick some third-party crate which in all likelihood is totally unvetted.
The crate that they selected could equally turn stale and outdated quickly if its a small one-man-band Github party (a not unfamiliar story these days).
Hence, having a standardised baseline available in stdlib is no bad thing IMHO. It brings "sane defaults" and forces anyone wanting to do different to make a thought-out decision, not just grab whatever Crate "looks good" so they can get on with coding.
That's okay though. It's better for some devs to (temporarily) pick some bad crates than to permanently include some broken legacy APIs in the standard library that need to stay there due to compatibility issues. Even Python 3 couldn't get rid of a lot of code that just should not be in the standard library.
The fact is that in practice, for most “standard” functionality that isn’t in the stdlib, there are well maintained, well vetted crates written by well known authors (or even developers of the stdlib). These are not hard to find, either by asking around or looking at what other crates use.
Rust’s stdlib is consistently of high quality. I can use everything in it without worry or concern. I can’t say the same about Python.
Keeping deprecated functions around still requires some maintenance burden, because you can’t break them just because they’re deprecated. That maintenance burden might become pretty extreme if we’re talking about something as complicated as an HTTP server module, as some folks are asking for in this thread.
I also personally don’t want to see the standard library littered with failed and deprecated experiments. In addition to the maintenance burden, it adds confusion when you’re learning the language or trying to discover how to do something.
That this is the norm for a language that focuses on security is mind-boggling.
Didn't we learn anything from the NPM mess?
Yes, but the crate dev likely offers no maintenance guarantees.
A bad stdlib had to be maintained forever (and potentially divert new users from better options)
Code can be deprecated but it is often a long drawn out process.
The big difference is versioning (eg. you can have a crate that works on old compilers/stdlib, you can pull an older package version to new compiler/stdlib) and maintenance burden.
Coming from Ruby, there are lessons to be learned. Ruby has a large stdlib, like you seem to want. But a lot of stuff in there is outdated. So much, that many, even most, people, projects, frameworks immediately replace them with a community version. Sometimes because they are actually better maintained, more stable, faster, cleaner and more secure than the ones in stdlib. A similar thing is seen in Ruby-on-Rails, which adds features and even entire frameworks with every release, but which many people swap out for their own preferred lib almost immediately.
This is inevitable and obvious. And, IMO should be embraced: deprecate them from stdlib, and leave it to "the community".
> They will (semi)randomly pick some third-party
Again good lessons can be learned from Ruby (gems) here. People will pick a "random" one only if there are no canonical, defacto-standard libs (gems) out there. But for some gems there is a clear, singular goto option and everyong will pick that, turning it into something of a stdlib. A good next step would, IMO, NOT be to then pull those libs into the stdlib, but, instead, to make the "not-fully-stdlib-but-also-not-random-community-provided" into a distinct category of libs.
And is very aggressively moving stuff out of stdlib to three concentric circles of gems; “default gems” which are almost like stdlibs (and still tied somewhat to Ruby versions) but are separately maintained and can be updated between Ruby versions, “bundled” gems that are usually distributed with Ruby, and just plain regular gems.
It doesn't have to be that way, though. Why can't there be first-party crates? If the Rust core team is adding functionality to stdlib why can't they add functionality to a crate instead? Then you'd have a collection of first-party, vetted crates for devs to choose from.
In most GCed languages it wouldn't matter so much because you'd return a boxed `Iterator` or `Future` or what have you. But in Rust you generally want to avoid the allocation.
Ie, if I wanted an enum of either a string or an integer, it becomes "Either<&str, i64>".
But what I wanted is that it's either a string identifier or the database Id of something to be later referenced, which might be better described as "enum IdentOrDbId { Ident(String), DbId(i64) }".
This is of course a much simplified example of things I've faced.
fn some_func() -> impl SomeTrait {
if some_condition {
Either::Left(a)
} else {
Either::Right(b)
}
}
Both a and b will implement SomeTrait which is all callers care about. However, because they're structurally different they must be wrapped in an Either that delegates all methods from SomeTrait to a or b respectively.For object-safe traits where this would be possible, you can at least do this at the cost of an allocation, as you probably know:
fn some_func() -> Box<dyn SomeTrait> {
if some_condition {
Box::new(a)
} else {
Box::new(b)
}
}How could you ever possibly, gasp, write it yourself? Oh the horrors of computer science.
Seriously, many times I find myself needing only a fraction of some provided library.
In a compiled language like Rust, that should not matter, isn't it? The binary-size, performance or attack-surface should not increase from code that is unused as it won't be in the resulting binary. Or did I understand it completely wrong?
Maybe. I think .NET's core libs are excellent. So are Go's. I'm sure it's a maintenance burden, but man... It's so nice to be able to build a project with maybe 1-2 dependencies instead of 100s (as in my typical Node and Ruby projects, if you count transitive dependencies). It's hard to overstate how much of a strength I think a good stdlib is.
Go just dodges that trend and does the 20th century thing, as it does for many other design decisions. Just as it has common data structures as hardcoded language features, instead of the ability to build them as abstractions.
To be clear: One can take the position that the trends go in the wrong direction and Go is right to reverse them -- that's a matter of opinion. I just don't think it's fair to argue Go is the language that does the more modern thing.
The main reason I've wrote so much python in the last 10 years is due to it's stdlib being comprehensive enough to do 95% of the tasks I need without adding any dependency.
This despite the fact that I never was super-fond of python's syntax and ideology, although I just learned to accept it. I was writing a ton of perl before that, and with python I could do more with less "CPAN". I would have _never_ made the switch without.
A good stdlib ensures decent performance, stability and overall code quality to your project. Without that, you need tons of dependencies along with version pinning (as developers nowdays understand semver even less than 20 years ago) and duplication due to your dependencies picking different packages as their own base due to the lacking stdlib.
I hate the sort of ecosystem which is built around this pattern. See npm for one extreme, although I see cargo not too far away in the horizon.
How then? I can give counter examples of the opposite easily:
An extensive stdlib ensures decent performance: https://stackoverflow.com/questions/31548680/why-is-python-3...
An extensive stdlib ensures stability: i'm not even sure how, with good version pinning it should always work, regardless of the it being std lib or otherwise.
An extensive stdlib ensures overall code quality to your project. This one I agree most with, but because the std lib sets the idiomatic writing style of the project. I'm not how important the size of the std is for this to work.
This example is about a language issue, not the stdlib. And it's only slower on purely computational code, which Python is known to be bad at anyway, as a tradeoff to avoid overflow issues.
> An extensive stdlib ensures stability: i'm not even sure how, with good version pinning it should always work, regardless of the it being std lib or otherwise.
Version pinning is a bad practice because it slows deployment of security updates. It also only works for end applications, as libraries cannot reasonably pin their own dependencies.
> Version pinning is a bad practice because it slows deployment of security updates.
How is that not true for stdlibs?
> It also only works for end applications, as libraries cannot reasonably pin their own dependencies.
Really?
> Really?
At least not usefully if types from those dependencies appear on the API surface.
And Rust ints can overflow. It's a tradeoff.
>> Version pinning is a bad practice because it slows deployment of security updates.
> How is that not true for stdlibs?
Because, if without pinning, the package manager always gets the latest available version and installs it for all applications on the system once and for all. When pinning dependencies, system administrators need to wait for every single application to update its pin.
There are provisions to do math that won't overflow or that can saturate. For example https://doc.rust-lang.org/std/primitive.u32.html#method.chec...
As an example, most of STD (the stuff outside core) makes the assumption that a nonfallible allocator exists. This is an entirely reasonable assumption for any high level programming language... yet it's one of the biggest complaints about Rust's standard library from systems programmers. And so a not-insignificant amount of (mostly volunteer) developer time has been spent modifying very basic data structures and APIs to support the (not so niche) use case of fallible and pluggable allocators.
If you're working on a stdlib where the question, "what if my allocator doesn't work" is meaningful, it's not a big jump to much more complex questions about how to implement "standard" features in other languages that simply don't have the same concerns as a systems language like Rust - making it much more reasonable to shove off the responsibility of implementing those features in libraries out in the ecosystem.
And I think that's wholly in line with the space that Rust occupies, which is next to C++ (which also has a lacking stdlib for "standard" features), but at least has a good enough package manager to deal with it.
Ironically, Python makes the best desktop calculator. Go figure.
At this point more of Java's standard library shouldn't be used than should. Java literally has multiple UI implementations in the standard lib and none of them are the recommended method of UI development in Java.
As far as I am concerned the only thing worse than having to use a package manager to make choices, is having to use the package manager to make choices to replace the dead ends codified in the standard library.
The go stdlib has the compatibility promise. Managing ANY external dependencies is exactly what causes breaking changes to be introduced over time. Think of it as a long term support plan on all your packages.
python had a HUGE stdlib, which was its downfall. Go's stdlib is quite small in comparison. I'd say the kitchen-sink batteries included is the 20th centry idea, Not the approach go has taken.
With respect to mainstream 21st century programming languages, I’m only familiar with Go, Rust, and C#, of which C# and Go certainly have pretty comprehensive standard libraries. Other mainstream 21st century languages I can think of run atop either JVM or .Net and I believe they have access to the Java or C# standard libraries, respectively but I’m not sure if it would be fair to say they inherit those standard libraries or not.
The discussion is about large standard libraries vs. package managers. C and C++ are even older languages that had neither. Back then, the idea of having a large abstraction layer between the language and the OS wasn't even thinkable -- that idea didn't really appear before the 90s.
If you don't know the size of Java's standard library in the 90s, it's maybe risky to imply that it must have been small. :) Kidding a bit. But to give a hint, it included two different incompatible GUI frameworks by 1998.
JavaScript is from the 90s, but wasn't a standalone programming language until Node.js, which was released in 2009.
C# is the newest non-Go language you mention with a large standard library. It was released in 2000 (so in the 20th century if we're being pedantic), and even it has moved a lot of stuff into Nuget packages that used to be built in. For example, the entirety of ASP.net.
Hence why everyone kind of expects POSIX to compensate for the anemic ISO C.
While ISO C++98 was built on the same anemic principle, due to its relation to C and UNIX, all major C++ compilers had rich frameworks, which unfortunately WG21 ignored.
Agreed, but this is my point. I don’t think the distinction between “20th century vs 21st century” is particularly meaningful, but I’m responding to the assertion that 20th century languages are characterized by large standard libraries—how can that be the case if standard libraries didn’t really exist apart from a few languages in the very final years of the 20th century?
> If you don't know the size of Java's standard library in the 90s, it's maybe risky to imply that it must have been small. :) Kidding a bit. But to give a hint, it included two different incompatible GUI frameworks by 1998.
Fair enough.
> JavaScript is from the 90s, but wasn't a standalone programming language until Node.js, which was released in 2009.
No, but it had a standard library (browser APIs) long before NodeJS.
> C# is the newest non-Go language you mention with a large standard library. It was released in 2000 (so in the 20th century if we're being pedantic), and even it has moved a lot of stuff into Nuget packages that used to be built in. For example, the entirety of ASP.net.
But enough remains in the standard library for it to be considered “large”.
Anyway, if there are only a handful of 20th century languages with large standard libraries (all clustered around the turn of the millennium) and seemingly only one mainstream language in the 21st century with a small standard library (Rust), I think the original claim that Go is the exception among 21st century languages is incorrect.
Take HTTP, for example: the decision of the data type to use for storing headers is easy, because there are really only four possibilities, two binary decisions to make: ① do you use string or []byte; and ② do you use map[T][]T, or join values with commas and special-case that pesky Set-Cookie header somewhere and use map[T]T? And so map[string][]string was fairly obviously the best choice from the start, and I think still is—in Go.
Meanwhile, in Rust, are you going to go Vec<(Vec<u8>, Vec<u8>)>, can you get away with HashMap<String, Vec<String>>, do you store a central buffer and work with slices for fewer allocations, or do you say “no, that’s stupid, headers aren’t strings, they’re just serialised as strings” and go all fancy typey in one of a variety of ways, some the most efficient of which depended on GATs which are only recently stable?
Go could have net/http from the start. I don’t know if there’s something better now (I don’t use Go), but I expect that the better would still be very similar in API.
If Rust had had a std::net::http at 1.0, it would certainly have been deprecated by now. Probably even over four years ago.
(Disclosure: I wrote the first de facto standard HTTP library in Rust, rust-http, back in 2013. Then in 2014, realising its design was a dead end, I went to write a new one from scratch, Teepee, but never finished it because of decision paralysis, others took up much of my work and finished the concept off in Hyper, and I’m glad I got out of the critical path and I’m glad they took it up.)
The problem with standard libraries in general is that it's not really possible to adjust the API later if it turns out to not be well-designed. And it turns out that "oops, we got the API wrong" afflicts, well, literally every standard library I've ever worked with (note: this even does include Rust, as young as it is). Examples include:
* C/C++: wide strings, locale support, std::unordered_map (it prevents you from using a good hashtable implementation)
* Python: mail parsing libraries, http requests [and this even after having an exceptionally painful major version that allowed them to break compatibility!]
* Java: java.util.Date, java.util.Vector [as opposed to java.util.ArrayList]
* Rust: raw FD support, std::io::Read interactions with partially-uninitialized buffers
There is something you notice when you look at standard library misfeatures, which is there are different kinds of issues. The simplest issue is something like locale support in C/C++: you can just simply not use it, and everything will be fine. On the other hand--and this afflicts Python the most of any language I'm familiar with--having a broken implementation in stdlib can dissuade the community from making a good version of what you want (this is what happens with the mail format stuff). The worst possible kind, though, is when you make a core type with an utterly broken API--and this is what java.util.Date qualifies as.
Having "batteries included" makes it more likely you get more severe kinds of API failures in the standard library. Already, the Rust ecosystem has had evolution in core package libraries that allowed it to absorb poor API design--consider the shift from error-chain to thiserror/anyhow, or the futures 0.1->0.3 change.
Go programs pull in deps, of course, but it's unusual bordering on unidiomatic to pull in a dep that changes the general programming environment (idiomatic Go sticks with the data structures and, notably, concurrency primitives in the stdlib, net/http remains the de facto standard HTTP interface, things tend to build on top of database/sql instead of replacing it, for the most part the stuff in encoding/* is canon, &c). That's not a plus for Go, but it's a contrast with Rust, where crates routinely redefine or refine the underlying Rust programming environment (best example is anyhow, of course). So Go programs rely heavily on the stdlib and its abstractions. And my perception is that by and large Go devs are pretty happy with it?
Maybe DNS would qualify as such a botch; maybe the interaction between sockets and contexts as well. And we'll see what chaos erupts from 1.18 generics.
(None of this should be construed as in any way a dig on Rust, which I find frustrating but also enjoyable to work in, and whose expressiveness and utility advantages over Go I respect).
However, the garbage collection process itself sometimes introduce a noticeable pause in execution, which can be unacceptable in certain applications. Especially in critical real-time applications.
(That GC pause won't be a problem if your program mostly just waits for user input the majority of the time).
For an extreme example, you don't want your car's airbag controller to be paused for garbage collecting during a crash.
(For some context, interested in Rust since 2009, similar as with Go, but not involved at all, whereas contributor to Go pre-1.0.)
First thing, is that I was frustrated with lack of simplicity vs. Go for a long time as well. Finally, recently I got it: AFAIU it's a case of different priorities. In the triangle of simplicity-safety-performance, Go loves all of them, but in case of conflict, chooses simplicity (thus, most notably/infamously, we get GC and nil). Rust also loves all of them, but in case of conflict chooses safety AND performance. What's freaking crazy IMO is the "AND" here, which I see as a huge thing. And it instantly also explains to me a tension in the Rust community between safety and performance camps, infamously most visible around usage of the 'unsafe' keyword. Yet in a barely-managed marriage between safety and performance, simplicity is the heartily beloved friend, who still just gets silently shown out of the room when a serious row starts between the couple, until they're ready to open the door back, and with patient smiles listen to some friendly suggestions.
Secondly, I bumped my head into a wall a few times until recently I tried the O'Reilly "Programming in Rust (2nd ed.)" on some recommendation from Reddit. The "2nd ed." part is important here, because it covers a few relatively recent important additions to Rust, that I found I was teeth-gnashing frustrated without before (coming from Go), namely: anyhow, thiserror, and (to a lesser extent) async. Edit: Two bonus personal recommendations for the book: (1) I got a job in Rust after going through it and then testing my abilities on some personal project, where I finally felt I'm managing to do regular non-fancy-shmancy (i.e. web, sqlite, GUI via iced, but no macros and avoiding lifetimes whenever possible - if curious, the project is: https://github.com/akavel/backerrs) coding, and can work around lifetime issues (somewhat faster or slower but can, and often just falling back to .clone()/Rc); though in all honesty, they kind of didn't really test my Rust skills, to my huge surprise, and trusted my smarts shown in Go & C++ experience + passion for the project; (2) I'm carrying the book with me to workplace every day and definitely checking things in it from time to time.
Maybe unified interface to work with DB.
Cryptographic functions while useful age poorly, and require constant change.
Serde while extremely useful won't fit every usecase. Sometimes you want something smaller or faster.
Http(s) clients also tend to age poorly. Python also had http client/server in std lib that aged like warm milk.
For a thing to be in std, it needs to be imo something you don't want implented in several different ways. Something that is essentially solved and will change very little over time.
Async runtime is neat, but it tends to be more trouble than it's worth. And I don't think any design has emerged as universal way to deal with it.
Time however has/should have a single representation.
Without a proper async runtime it is very hard to write portable asynchronous code, as each library is tied to a specific runtime.
I think the hard problem in practice is that headers and templates make for a very fuzzy boundary between library code and client code. Calling C++ from Rust already works fine for traditional OO code, but it’s hard to imagine that anything could ever use modern templated C++ code that isn’t a full superset of C++.
I don't think templated C++ code needs to be a full superset of C++. For example, cxx provides bridged implementations for CxxVector. If cxx provided an easy-to-use mechanism to define your own bridging type without a lot of boilerplate, that could open up far more interop than is possible today.
As a developer, what I really want to hear is that Rust 2022 will be basically Rust 2021 with some bug fixes and performance improvements.
Let's hope we get there next year.
That happens to most actively used languages. C# has seen some major evolutions in recent years and is 22 years old now, Java is 26 years old and has some major changes compared to what it was 7 years ago, and you can no longer discuss C++ (37 years old) without mentioning C++11 along the way.
Rust is perhaps the language that people SHOULD be using, but likely won't. Until someone can offer something as simple and easy to learn as C and also can automatically do the things Rust provides without asking the programmer to give double in mental effort, I don't think we will replace C in a major way.
Rust is much much more gentle to learn than C: when you don't understand what a pointer is and how it works, you get an explicit error message given by the borrow checker and you can just ask on the official discord channel for beginners and you've solved your problem.
If only we had discord 12 years ago... The reason you struggled with C is simple: lack of theoretical knowledge. Your teacher should have started with core workings of a CPU before he showed you C.
Maybe he did, but you simply didn't bother to learn?
To really learn about the innerworkings of the CPU, you must read a book about...the innerworkings of a CPU.
That's simply not true. There are all sorts of learning resources that aren't books. I have personally learnt a ton about the inner workings of CPUs by following the /r/rust subreddit for example.
Most program languages are accessible to people without a university degree or the desire to read a doorstop book on the subject. C and C++ are a notable exception to this. I don't know how you can argue that a language is easy to learn whilst simultaneously holding that it requires a university degree.
But C doesn't map to the "inner workings of the CPU", it maps to a certain abstract machine, defined in the C standard [1]. If you think that C maps to an actual CPU, you're already using C wrong, and it probably shows – in the form of undefined behavior bugs.
[1] standards, actually, pick your preferred version
Holding this kind of argument in a thread about how Rust is too hard is a bit strange though…
That's some very thoughtful and noble goal. Maybe people who use C++ (and bunch of other languages) are not the ones whining.
1) is as safe and as fast as Rust, or at most 1.5x slower
2) offers "fearless concurrency" and easy, safe, and efficient parallelism
3) has sum types and a good static type system
4) has great tooling and package management (see cargo)
5) has a vibrant and growing ecosystem
So far, that language doesn't seem to exist. Most fail at points 1+2.
1) reasoning about performance is just too difficult (due to lazy evaluation)
2) the community seems too focused on providing ever more abstract abstractions instead of practical solutions to actual problems
3) purity and freedom from side-effects cause a lot of friction and make many simple problems really hard; the libraries and patterns to solve that problem are too complicated for me to comprehend, so maybe I'm too dumb for Haskell (though I don't have any problems with Rust, so...)
> Being in the position of "I need to learn a first systems language, should I pick C++ or Rust" is not very common, IMO.
What makes you think that. Everyone who learns systems programming is in this position at some point. Perhaps not if they learn at university and the language is chosen for them, but that just pushes the choice onto the university itself. And universities are increasingly offering Rust courses.
Of course, plenty of programmers aren't systems programmers and never will be. But that doesn't negate the need for systems programming languages, as demonstrated by the continued use of C and C++. If you do need a systems languages then Rust can make a good case for being the simplest. And could well become the de facto standard over the next few years.
C++ uses far exceed systems programming.
Rust to me is starting to feel like how Haskell was a decade ago, where it seemed like everybody was talking about it but serious adoption was always just on the horizon.
But maybe my expectations are just too high. It seemed quite exciting at first to see everything being rewritten in Rust but I guess that’s not how the software world really works. Old projects are entrenched because they take many years of dev time to mature
I think you might just not be aware of how widely adopted Rust already is. Google, Microsoft, Amazon, Dropbox, Cloudflare to name just a few companies already have important projects in Rust. Curl is adding a Rust backend. The Linux Kernel hasn't committed yet, but groundwork has begun and it's looking like it's going to happen. Serious adoption has already happened.
You're right that we won't see mass rewrites (although there have been some). That's just too big a project. But new projects are increasingly choosing Rust. It'll be a decade before Rust is the de facto standard if it happens. But personally I consider that quite likely.
Edit: Ok maybe a bit dramatic, but I really hoped we would get working modules with c++17 and here we are still years away...
Granted the only way to fully enjoy them is being on Microsoft ecosystem, but hey plenty of us are.
It was the phenomenal Rustlings course that got me over the learning hump.
Of course most of the work gets done by the compiler safe guarding and guiding during development. People make noise about lifetimes etc but once you are ready to pay the penalty of Arc (and in most cases if you are using lifetimes you are already on the verge of using Arc). Same with using cloning as needed. End of the day, these incur a predictable and acceptable performance penalty than many other languages do while providing good safety.
It is not about how easy is it to write rust. It is about how, as a C programmer you are going to explain that your code is safe.
I know that as a long time C programmer, I still make occasional mistakes that lead to memory corruption.
In production code, there are still way to many pointer bugs. Use after free, etc. That needs to end.
And I hope that people stop preaching and would live and let live.
There are easy languages like Python or Go. But they are not suitable for many low-level, high performance tasks.
Rust is competing in the domain of easy to use languages. It is about low-level system code.
Edit: Rust in not competing in the domain of easy to use language
Probably, yeah. At least in a world where openssl is actually so hard that doing stuff yourself seems like a reasonable idea, because theoretically secure doesn't do anything for you if the thing is too hard to actually use - there's a reason PHP utterly dominated webdev even when it sucked for security.
> Rust is competing in the domain of easy to use languages.
Then it loses. If you meant to write that Rust is not competing for easy to use, then it loses separately, because technically superior but too high of a barrier to entry still loses (there is a reason we aren't all exclusively running software written in Ada on OpenBSD).
In a sense Rust very much is competing in this space. Consider the extensions to JS (wasm), Ruby, Python, and others that make it easy to call out to Rust. This is being used for performance critical sections of code (or access to high quality stable network and security focused libraries). This competes directly with that native language but offers a path that is easier than C or other options.
Rust appears to be finding a lot of success in that space.
Newsflash, it's not a language's job to make software safe. It's job is to make programmer's job as simple as possible: ie. writing new software. If your language fails to do that, people will not use it, plain and simple.
How else could you explain the popularity of languages such as Python and Go?
I didn't really understand Rust, until I saw a Cppcon talk about how to use STD.unique_ptr correctly, and I realized that the rust borrow checker is just that talk implemented in a compiler.
Maybe your criteria isn't universal?
However, if the project needs a low-level language. Then skip C and C++ and use Rust.
Almost from the start, high level languages have been about safety. In assembly, memory is untyped. That leads to way too many bugs. So languages evolved to get more eleborate type systems. Compare for example K&R C with lacked function prototypes with current C that does have them. That saved huge numbers of bugs.
Traditionally, garbage collectors had to be used to maintain memory safety. However, that conflicts with many of the uses of C. So Rust had to come up with something that is both safe and compatible with C.
What kind of logic is that? "Because Google sells your data, I don't have to worry about memory safety bugs in my code." Come on.
1. https://insights.stackoverflow.com/survey/2019#technology-_-...
2. https://insights.stackoverflow.com/survey/2020#technology-pr...
3. https://insights.stackoverflow.com/survey/2021#technology-mo...
So, I agree with you, it will probably not become a replacement, but it succeeded in providing a credible alternative that has been used by many already.
C is neither simple nor easy to learn. Incorrect and buggy C is simple and easy to learn.
If you think C is "simple" and "easy to learn", your C code is almost certainly full of undefined behavior bugs and security holes.
Writing C with a "how hard can it be?" attitude is a great way to get a CVE named after you.
Rust won't make systems programming any easier, it will still require the usage of unsafe part of the language. Only, you will also have to deal with a much more complex langage than C. That is why Rust has failed to replace C and C++.
- types of varying width (how big is an int?). Rust solves that
- null terminated strings. Rust's are saner
- what happens in an overflow? What are implicit casts? Rust clarifies those edge cases
- standard libraries often use NULL to signal error, no actually -1, no actually non-NULL. Rust has Result
And I haven't even scratched the surface...
All those cases are pretty basilar and happen everywhere. For me it's clear that C is much more complex than Rust if you think about the edge cases. All those safeguards are vital.
But yes, Rust is a much bigger language than C so it won't replace it for really low level, scarce resources tasks. For that look at Zig
By the way, it is sooo easy to test for them,
https://googleprojectzero.blogspot.com/2021/12/this-shouldnt...
Rust is first a system programming language with zero-cost abstractions with the least possible pain, then it is a safe language, way safer than C++.
In any case I am following the community and I have a hard time finding people saying C++ is nice for them. There are few people who have been coding C++ for 20+ years and "love" it but they are far and between. Almost nobody tried both Rust and C++ and continued using C++ for new projects.
So I predict Rust won't replace C, they have different use cases, but it will make a dent in C++.
Why won't it? I haven't really used rust or LLVM before, so I am genuinely curious.
The way I take it, the rust compiler team can either spend their time trying to get to being self hosted, or they can spend their time making improvements to the language.
It is a bit hard to achieve such goal if improving Rust requires to some extent, to keep writing C++.
Naturally some day the compiler might be fully bootstraped, however that implies throwing away the work being done by legions of C++ devs on LLVM (same applies to be front ends being written to plug Rust into GCC).
I recommend the 2nd edition Oreilly book + writing lots of code for about a month or possibly two. After that, I think many will agree it isn't nearly as hard to write as they initially thought it would be.
The biggest bonus: Writing Rust is very fun. I can't pinpoint why this is, but I totally understand why it keeps getting voted favorite language. A total joy to write.
Add the stdlib and you have plenty of confused faces who after some time fail to see the point.
There are toolkits out there and game engines picking up steam.
My guess is that for a GUI in Rust to truly shine it will have the hard task of working both in native OSes and WASM on the Web. People are working on these frameworks, but most are pretty limited at the moment depending on needs. (If folks believe it’s better than that, please share, it’s only a space I dabble in sometimes)
Given the learning curve of Rust and the lack of tools it's still a bit of a gamble to choose Rust over C or C++ IMHO. Why take that risk when the benefits aren't entirely clear cut.
In 30 years, do we really expect to be programming in some machine-human intermediate language? I hope that we'll be having an open ended conversation with the machines to iterate our intent, with working software at most stages along the way.
I.e. will it matter what language anyone uses? Here, take this software renderer I wrote in Python, and translate it to C++. "Conversation" about choices and ambiguities ensues...
Just as when people asked this 30 years ago, yes, though from our perspective today the tooling may seem near magical.
This is actually entirely feasible, although perhaps not open-ended conversation. Instead it could be that you feed the machine training data which describes how to solve a particular task, and the output is a program that solves that task. So we would all end up being ML engineers.
Scary I know...