This is my reply to Rusts call for community blog posts.
I’m known for being quite happy with Rust as is. Indeed, my first post on focusing on stable Rust was more than 2 years ago ;).
Also, note that I’ve been interested (and practically involved) in the growing and adoption of programming languages since around 2004, which was when I started doing users support for Ruby in Germany.
I am of the opinion that programming languages are never fully understood, neither by their users, nor their creators. What may seem a hard problem yesterday suddenly gets solved by a standard practice tomorrow, without any changes to the language.
I’ll give an example: which language do you think of when I say “duck-typing”? Probably Ruby.1 That wasn’t always the case. Indeed, Ruby was already quite an old language when it got introduced as a strategy: in Ruby 1.8.0. That was almost 10 years in! Later came software like Rails, Sinatra, Merb, DataMapper or, nowadays rom-rb. All these projects have something in common: they invented new ways to work with the language. None of them changed the language. The legendary “instabilty” of the JavaScript world? All people inventing new approaches. This is for a very loose definition of “inventing”, most inventions in the programming world are someone porting an existing concept and making it approachable. Rust is no different.
I’ve seen more than one language designer taking hasty notes during a conf talk because someone was doing something with their language that they didn’t know was possible.
Programming languages are so complex that they constantly give new possibilities to combine their features in new ways without changing them. That also makes discussing them so hard and prone to talk past each other, because everyone has a very different way of viewing them. For example, I tend to not give so much about small details in code and am very fine with boilerplate. Systems construction is my interest.
I also am of the opinion that language adoption is far more about connection points than about many small qualities of the language. I think, for example, that JavaScripts current position in the programming world is entirely understandable and to a large extend rational. Haters disagree.
With that background, I’d like to say that we don’t understand Rust to some point. We don’t even understand Rust 1.0. For example, all the techniques in Pascals great API patterns guide are possible since almost forever. All of them took someone a while to properly figure out. This document could not have been written on April 15, 2015. My major sport for 2015 was finding libraries that were relying on nightly features and teaching people how to do that with stable Rust at no cost.
This isn’t a complaint, it’s the joy of working with a programming language, especially a new one. And we tend to forget that Rust is a damn good programming language. I’m also not saying that we shouldn’t continue to evolve the language, for example the addition of custom derives in Rust 1.15.0 was extremely important and helping a lot.
But still, I think, we should start working with the Rust we have and use this year to push this good language into the world.
Because we can’t Rust, we currently can’t produce solutions that will surely stand the test of time. That’s fine.
There’s more than a couple of things missing in the Rust world that
are slowly becoming serious issues: for example, we still don’t
have a stable, properly documented HTTP client (not even as a binding,
mind you). This is also strengthened by fundamental libraries for those
tasks being notoriously unstable, too: for example futures
and tokio
. This has huge repercussions to the whole
ecosystem: especially futures
usually describes public
interface of your library. Breakage of futures is breakage of your
interface.
All of the mentioned libraries are interesting in their own right. Indeed, you can learn quite a lot about API building from them. Hyper is a great example of how to use Rust fundamentals (plain ownership and borrowing) to great effect. But sadly, all of them are not properly documented or are even up for yet another big rebuild. I see a lot of good plans there, but they don’t fix the biggest problem: lacking stable availability. Because of that, all these subjects are still considered “advanced Rust”, without good reason to.
With all respect to authors of many fundamental libraries: 1.0 isn’t the end of the world. Many libraries are in a great shape. A 2.0 is possible. The Rust world would vastly benefit from a 1.0 and proper documentation.
Stabilising and documenting fundamentals opens multiple paths: it
gives people interested in building higher-level software such as
frameworks a realiable target to build against. It also allows competing
implementations to have a good reference. Maybe, at some point, it turns
out that may
becomes the
new hot thing. So be it!
I’m sure that - five years in - some of the libraries we currently push for 1.0 will not stand the test of time and will be replaced. This will introduce a cost to the ecosystem. I don’t think this cost can be fully avoided. And especially, fearing this cost has a current cost, that of constant insecurity about things considered basic in other programming languages.
One of the reasons I like using futures
,
tokio
and hyper
as examples is because I
learned so much from them and can speak about them in very positive
terms. They all found and implement very interesting patterns to work
with the language. Sadly, these gems are still hidden in those
libraries.
The Rust documentation is often applauded - rightly so - but is very down to the details. What’s currently lacking is documentation for specific contexts, for example beginner, intermediate and advanced users.
But how do we competently work with Ownership and Borrowing? How is it useful beyond memory management, especially in API design? When do you use borrows, when is it better to choose - for example - to pass indices or other token values around?
This plays into another issue: How do we build large programs? How do
we build components? How do we glue them to each other? How do we build
frameworks? How do we share implementations properly? How do we manage
build times in these cases? All these questions are not answered, not
even in the first iteration. rustc
and Servo, as some of
the oldest large Rust programs give pointers, but because of their age,
they are bad templates as a whole.
Again, I’m sure that some of the approaches we come up with will be considered dated even 2 years from now, but that’s no reason to not get started.
Currently, many Rust projects are single-person affairs. There’s regularly attempts of forming teams around certain subjects, other subjects - most famously gaming - already have large projects. These are the projects that regularly tackle these kinds of issues. Form more of them!
Rust has managed a great many things in the recent years: the Rust language showed that systems programming and working on a higher level can be done under one umbrella. We created tooling that is seen as a benchmark in the industry. Our community work - as many gaps as it has - is seen as innovative.
But Rust is still a young language and we should consciously stay one. We still need to get a handle on it and we still need to learn it. Things not being settled is not only a drawback, but also a chance to find new things. But as with all things we build, solid fundamentals allow building sold things on top.
I’d like to thank everyone who adopted Rust in the last years and found value in it. You helped us shape our grasp the language tremendously.
Also, I’d like to personally thank Alex, Sean and Carl for their work
on futures
, hyper
and tokio
, I
learned a lot from you.
Also, thanks to @withoutboats for suggesting many changes to the language and following the discussions through to the end. I’d like to particularly highlight the first two module RFCs and especially the ongoing discussions around Results. The module RFCs lead to (in my opinion) a far better better design in the end, I’m sure there’s going to be a good conclusion to the Result story.
top