Please avoid the cookie jar

Hi all,

We had a production user call yesterday and found a little problem with the train model: it makes it easy to have our hands in the cookie jar that is nightly, because all of its features might be released "soon".

I've got a little hobby: porting libraries that have the sentence "compiled on recent nightlies" in their README to stable Rust. In my experience, these changes are often pretty minor: for example, the collections and path_ext features are often used, but only to use one of their methods that is still into staging. Porting to stable is often just the work of having a look at the implementation of the unstable feature, port it over in some way[1] and then run on stable.

We should - as a community - get used to using stable unless you do things that definitely need future nightly compiler infrastructure (e.g. for cross-compilation and embedded things). Especially, we shouldn't ignore stable for things that are perfectly fine to be implemented in stable Rust, just for being a little less convenient. Also, finally, performance reasons are also not a good one: having a more efficient implementation for something available in a feature-gated API means that Rust stable just isn't there yet - implementing something efficient and fast on top of that should always be seen as something not ready for the general public, but only for testing purposes - a toy, basically.

Stable gives a lot of guarantees and is what production users want to use - we should make sure that it is the baseline we implement against. It makes the work of those trying to propagate the language easier and makes sure Rust fulfills the guarantees it wants to give.


[1]: Example: Remove PathExt requirement · skade/wtftw@c41962e · GitHub


I haven't yet programmed on stable (because clippy doesn't work on it), so I cannot say too much about it.

But IMHO it's perfectly fine to develop on nightly – as long as you don't use any #![feature(…)] flags to your code or rely on any library that requires nightly, you can always compile your code on stable. This allows you to use lint plugins, while still having (mostly) a stable rust.

Of course there may be some subtle differences between the versions (i.e. breaking changes), which makes this strategy a bit risky. I'm not going to plug my RFC PR anymore, as I have the feeling it won't be implemented anytime soon. One can use a CI system to test on stable to alleviate the risk.

To be fair, Rust isn't ready in a lot of places. As far as I know, you still can't get compatible timestamps from the system clock and a file. You still can't implement your own search patterns (which means you can't do a parallel search, which means I'd have to write my own high-performance search code... or use nightly).

Having said that, I do already try to avoid egregious dependencies on nightly. I guess for me it's a question of effort: if the burden of forking and maintaining my own copy of unstable code is too high, I'll just depend on nightly.

What I'd like, come to think of it, is a clearer indication of if and how I can help with the stabilisation of unstable things I'm using. Pattern, for example; is that on track to be stabilised, does it need more feedback? I really don't know, and I'm not sure where to look. I know there's a discuss thread, but I'm not sure I should be popping in every time I hit an unstable API and pinging everyone in that thread.

Finally, it's unclear from your post, but if you're suggesting that I start using stable as opposed to trying to target it... come back and let me know when it's even possible to install multiple versions of Rust side-by-side without either having to run in a UNIX shell or constantly messing with environment variables and "shell launchers". I played that game once before, and I am so not going back.

1 Like

I still would not use Rust in production, whether or not 1.0 is here. There is still a lot of features that are unstable, and until we can figure out how to stop making breaking changes (because they still happen), id rather stay away from production Rust.

Of course, that frees me up to use nightlies :wink:

There's a balance here, I think... if everyone uses stable instead of beta or nightly, then there's a risk of stable or beta being buggy because no one has been testing out the code there before the next train. This is a problem I've experienced with Rails releases, and it's a negative feedback loop-- no one wants to use the beta releases because they're buggy, so no one reports bugs while a release is in beta, so beta gets released because no bugs have been reported, so the first minor release in a new major version is buggy, so no one wants to use the first minor release in a new major version because they're buggy... etc.

Ideally, everyone would use all three channels, but there are a lot of things we all would do differently with infinite time :wink:


I agree, though in some cases there are features which have trivial stable replacements.

I did an audit in Servo recently, and the majority of unstable usage was just this. Mostly legacy code from before the concept of stability was in Rust which took the wrong turn during a rustup and picked an API that would eventually not stay stable while a sister API would go on and get stabilized. (Or code after the concept of stability where we picked the first option that we saw would work, regardless of stability). A lot of these can just be replaced with calls to a similar stable API (the path example from above is just this). In such cases, we should very much try and avoid these unstable APIs, but for more complicated things, we should use nightly APIs if we feel they make more sense.


If I had a Travis CI like environment built into cargo, where I just say “compile with stable, beta and nightly” I would surely use that and built everything (if possible) to run on all versions.

That kind of cargo feature would make sense. It would make us want to write automated tests to not be fonced to do them three times.
It would show us differences in the versions, regarding speed, available APIs and bugs.
It would also make the resulting code more stable, due to the better testing.

But I will stick to nightly until then.

The thing is, if nobody uses unstable features/APIs, they are unlikely to get stabilized. The point of feature gating and stability is so you are under no allusions as to what will or won't break.

I think that instead of trying to avoid using the features, we should instead avoid letting usage "leak". If your crate uses something feature-gated, it should do so in a way that is transparent to users. Your use of a feature-gate should not require use of a feature-gate in user code. This means breakage related to the feature is isolated to just that crate.

1 Like

It would be nice to be able to tag crates with Rust version requirements, including a "nightly" version that's perpetually in the future. If we could then get a cfg flag or something based on the compiler being used, it would let us conditionally introduce new features without having to force everyone on to nightly.

It might then be easier to create social pressure to make crates compatible with stable as much as possible. Currently, it's all-or-nothing. I had to use a scant few feature flags in cargo-script, and almost immediately after release I got people requesting things that would require more nightly features because "well, you already require nightly, so might as well." cargo-script'd be pretty crippled without those features, but I could probably make it work in stable to some degree.

This would also help highlight where nightly features may be necessary: a large enough hole in stable will start to show up as a hole in crates, where useful feature X isn't available because it needs nightly features.

Edit: Although I 100% agree with avoiding de-facto standardisation, it also feels like we need some way to actually test-drive new features without bifuricating the community into (filthy stable-using peasants and the glorious nightly-using master race|filthy nightly-using peasants and the glorious stable-using master race) [delete one].