Skip to content

Instantly share code, notes, and snippets.

@qinwf
Forked from brson/gist:1a40781a75113c6b344e
Last active August 29, 2015 14:21
Show Gist options
  • Save qinwf/a1b7a9c0dcf0ff94811d to your computer and use it in GitHub Desktop.
Save qinwf/a1b7a9c0dcf0ff94811d to your computer and use it in GitHub Desktop.

Rust feature staging and you

Recently I've been overhauling the mechanisms for introducing unstable features to both the Rust language and libraries. Part of that work landed for the 1.0.0-alpha release when we started producing warnings about using unstable library APIs, which I'm sure you noticed. Now the transition to the system described in RFC 507 is nearing completion, so it's time to remind everybody what's happening and how to cope with it.

We want to evolve the Rust process such that new features progress into the language in a controlled and predictable way, so that there are yet fewer suprizes about what is or isn't ready for use, and risk of new features becoming de-facto stable through early adoption is minimized. From now on every feature going into either the Rust language or the standard library is identified by a feature name, extending the feature-gating mechanism used by the language to the standard library.

For the remainder of the current development cycle, the nightly compiler will print a warning for all code that uses unstable features:

/home/brian/test.rs:1:22: 1:44 warning: use of unstable library feature 'core'
/home/brian/test.rs:1 fn main() { unsafe { std::intrinsics::abort() } }
                                           ^~~~~~~~~~~~~~~~~~~~~~
/home/brian/test.rs:1:22: 1:44 help: add #![feature(core)] to the crate attributes to silence this warning
/home/brian/test.rs:1 fn main() { unsafe { std::intrinsics::abort() } }
                                           ^~~~~~~~~~~~~~~~~~~~~~

During the first 1.0 beta cycle these will be converted to errors on the nightly channel, and authors will be required to explicitly opt-in to use of unstable libraries to keep their code compiling. On the beta and stable channels it will not be possible to use unstable features. We hope that between upstream stabilization and feedback from downstream authors we will converge upon a clearly-defined subset of the Rust libraries that are stable and that can support a substantial collection of the crates in the Cargo registry.

Feature staging for crate authors

Taking Rust from its historical posture in which unstable features are always available to one in which only stable features are available in production releases is a big and painful change to work through. As a crate author here's what you need to know:

To use unstable features you must always declare so by putting #![feature(foo)] at the top of your crate. While this has been true for language features for a long time, it is now true for the standard library as well. You are going to be doing a lot more of this in the short term until std stability for 1.0 has completely shaken out - hang in there!

Once the betas start and using unstable features without opting in becomes an error (wheras now it's a warning), it will be trivial to determine whether your code is using the stable - and backwards compatible - subset of the language: any Rust crate that contains no #![feature] attributes is written in a stable dialect of Rust.

As introduced, the current unstable library features are rather-coarse-grained. Some of those likely to impact existing code include:

  • io - All of std::io
  • os - All of std::os
  • path - All of std::path
  • hash - All of std::hash
  • collections - The collections crate and collections reexported from std
  • rand - The rand crate and its componentsn reexported from std
  • core - Everything else that's unstable in core
  • std_misc - Everything else that's unstable in std
  • test - The test crate
  • rustc_private - In-tree components that only the compiler should be using

During their unstable development feature names may change incompatibly, and in particular be divided into smaller subsets with different unique feature names. You are likely to see more features appear in the coming weeks as the remaining unstable APIs are scrutinized.

If this seems painful try to be reassured that we dearly want your crates to work on the stable release channel and will do everything we can to make that happen as fast as reasonably possible. In the coming weeks there will be a concerted effort to lift as much of the cargo ecosystem onto the stable subset of the language as possible.

Deprecation continues to work the same as it always has, via the 'deprecated' lint, so deprecated APIs can be opted into with #[allow(deprecated)].

Feature staging for rustc authors

For people hacking on rust itself there are a number of things to know. Firstly, the in-tree design is not intended to make your life easier - lots of stuff has to be tagged with metadata, but only incrementally more so than before.

Crates that participate in feature staging (i.e. every crate in-tree and no others) need to opt in. This requires the #[staged_api] attribute, which itself requires the staged_api feature. Being 'staged_api' is what tells rustc it needs to interpret the 'unstable', 'stable', and 'deprecated' attributes (while leaving the possibility of also using those names for non-staged-api purposes later).

Therefore every crate in-tree must say:

#![feature(staged_api)]
#![staged_api]

Nearly every crate that is not part of the standard facade should additionally include the crate header #![unstable(feature = "rustc_private")], which says 'this crate is not for public consumption'.

When adding a new public API to the standard library or to a crate in the standard facade, you need to tag it unstable and give it a feature name:

#[unstable(feature = "new_hotness")]
fn new_hotness() { }

Increasingly, this feature name should come out of the RFC process, and adding APIs without knowing what feature it is part of will be an indication that the development process is not proceeding in order.

Unstable features inherit so lexically, so you often only need a single one.

When a feature becomes stable you change the attribute from 'unstable' to 'stable' and add the 'since' attribute:

#[stable(feature = "new_hotness", since = "1.1.0")]
fn new_hotness() { }

'since' is the version in which that feature will hit the stable release channel and at the time of promotion should be equal to the value CFG_RELEASE_NUM in main.mk.

The stable attribute does not inherit lexically, so most items need to be tagged explicitly, including trait methods and inherent methods.

No single feature can be both unstable and stable, so if only part of an unstable feature needs to be promoted then it must be split into two features. All the 'since' attributes must agree for a given feature. A new tidy script enforces both these and can be run with 'make tidy-features'.

Deprecating an API can be done with #[deprecated(since = "1.1.0")], the same as before, but now requiring 'since'. Since both unstable and stable libraries can be deprecated, all deprecated attributes must be paired with either 'unstable' or 'stable'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment