# \[Pre-RFC\] Crate/item stability

**URL:** <https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425>\
**Category:** language design\
**Created:** [November 28, 2016, 1:09am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425 "2016-11-28T01:09:31Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![FaultyRAM](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/faultyram/32/2645_2.png) [@FaultyRAM](https://internals.rust-lang.org/u/FaultyRAM)\
**Post date:** [November 28, 2016, 1:09am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/1 "2016-11-28T01:09:32Z")

</div>

Looking for feedback on this.

[Rendered](https://github.com/FaultyRAM/rfcs/blob/crate-item-stability/text/0000-crate-item-stability.md)

---

<div class="post-metadata">

**Author:** ![stebalien](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stebalien/32/228_2.png) [@stebalien](https://internals.rust-lang.org/u/stebalien)\
**Post date:** [November 28, 2016, 2:22am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/2 "2016-11-28T02:22:53Z")

</div>

What does “reserved” mean?

---

<div class="post-metadata">

**Author:** ![FaultyRAM](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/faultyram/32/2645_2.png) [@FaultyRAM](https://internals.rust-lang.org/u/FaultyRAM)\
**Post date:** [November 28, 2016, 2:29am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/3 "2016-11-28T02:29:29Z")

</div>

`#[reserved]` means “reserved for future use”. It’s meant to be used on struct members, bitflags etc.

…actually, it probably only makes sense to use it on such items. Maybe it deserves its own RFC?

EDIT: I also updated the text with a short description of each attribute.

---

<div class="post-metadata">

**Author:** ![stebalien](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stebalien/32/228_2.png) [@stebalien](https://internals.rust-lang.org/u/stebalien)\
**Post date:** [November 28, 2016, 3:26am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/4 "2016-11-28T03:26:50Z")

</div>

Probably. Why a crate would need to explicitly reserve something isn’t obvious, at least to me.

---

<div class="post-metadata">

**Author:** ![FaultyRAM](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/faultyram/32/2645_2.png) [@FaultyRAM](https://internals.rust-lang.org/u/FaultyRAM)\
**Post date:** [November 28, 2016, 8:23am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/5 "2016-11-28T08:23:48Z")

</div>

Okay, it’s gone now.

I’ve also updated the RFC to allow multiple stability attributes on one item, because as it turns out, [that’s how the internal stability attributes currently work](https://github.com/rust-lang/rust/blob/0ca9967af75f7a279dcf4921f119b2602b41dd71/src/libstd/thread/mod.rs#L401). This means that `since` is now required on all stability attributes, which is a breaking change because that applies to `#[deprecated]` as well (it currently doesn’t require any fields). I think it’ll be okay though because `#[deprecated]` itself is still fairly new. (As usual this won’t be a hard error at first - that’ll be left to another RFC - but that’s only for items that have exactly one stability attribute, because the item stability rules assume that `since` is present for all stability attributes).

---

<div class="post-metadata">

**Author:** ![dhardy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhardy/32/2399_2.png) [@dhardy](https://internals.rust-lang.org/u/dhardy)\
**Post date:** [November 28, 2016, 12:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/6 "2016-11-28T12:23:50Z")

</div>

Why restrict the `since` field to **semver** version numbers? More generic version comparison [is possible](https://linux.die.net/man/5/deb-version). (Yes, I know [crates.io](http://crates.io) requires semver. I don’t know if that means everyone creating a crate uses it.)

I’m not sure that I like unmarked items being automatically considered stable. Why not have a third stability level for internal use, _unspecified_? From the point of view of compiling a _stable_ library, Rust should warn about unspecified items in the public API. From the point of view of using a _stable_ library, I’m not sure… possibly the default should be to warn about usage of such items (note that before any items are marked _stable_ the library is still considered unstable so this wouldn’t cause mass warnings, _provided_ that when stability attributes are added to the library they are added to all public items at once).

---

<div class="post-metadata">

**Author:** ![FaultyRAM](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/faultyram/32/2645_2.png) [@FaultyRAM](https://internals.rust-lang.org/u/FaultyRAM)\
**Post date:** [November 28, 2016, 9:47pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/7 "2016-11-28T21:47:02Z")

</div>

> [@dhardy](#):
>
> Why restrict the `since` field to **semver** version numbers? More generic version comparison [is possible](https://linux.die.net/man/5/deb-version). (Yes, I know [crates.io](http://crates.io) requires semver. I don't know if that means everyone creating a crate uses it.)

[RFC 1270 already specifies that the `since` field for `#[deprecated]` is semver.](https://github.com/rust-lang/rfcs/blob/master/text/1270-deprecation.md#detailed-design)

> [@](#):
>
> `since` is defined to contain the version of the crate at the time of deprecating the item, following the semver scheme. Rustc does not know about versions, thus the content of this field is not checked (but will be by external lints, e.g. [rust-clippy](https://github.com/Manishearth/rust-clippy).

The only difference is that `rustc` enforces this constraint instead of letting external tools handle it.

> [@dhardy](#):
>
> I'm not sure that I like unmarked items being automatically considered stable. Why not have a third stability level for internal use, _unspecified_?

A good suggestion! I've updated the text accordingly.

> [@dhardy](#):
>
> From the point of view of compiling a _stable_ library, Rust should warn about unspecified items in the public API. From the point of view of using a _stable_ library, I'm not sure... possibly the default should be to warn about usage of such items (note that before any items are marked _stable_ the library is still considered unstable so this wouldn't cause mass warnings, _provided_ that when stability attributes are added to the library they are added to all public items at once).

When _compiling_ a stable crate, absolutely, and it should become a hard error eventually. But I don't think _using_ an unspecified item should be a warning, because right now if you're using a stable crate, you'd expect items that aren't deprecated to be stable. (That was actually my reasoning behind making items in a stable crate stable by default, but I think unspecified is the superior solution here.)

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [November 28, 2016, 9:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/8 "2016-11-28T21:57:21Z")

</div>

I like the general idea of this RFC, but I’m not sure the detailed design is correct. Most significantly, I’m uncomfortable with _the language_ having a notion of semantic versioning.

I’m more in favor of something similar to the conditional dependencies RFC, in which the bulk of the work is handled by cargo telling rustc which attributes to turn on / off during compilation. I’m not sure if that’s workable, but I’d like it to be explored.

I also am unclear on how this interacts with the deprecated tag.

---

<div class="post-metadata">

**Author:** ![FaultyRAM](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/faultyram/32/2645_2.png) [@FaultyRAM](https://internals.rust-lang.org/u/FaultyRAM)\
**Post date:** [November 28, 2016, 10:47pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/9 "2016-11-28T22:47:30Z")

</div>

> [@withoutboats](#):
>
> I like the general idea of this RFC, but I'm not sure the detailed design is correct. Most significantly, I'm uncomfortable with _the language_ having a notion of semantic versioning.

Now that you mention it, yeah, we probably don't want the language itself being semver-aware. The crate version stuff can be enforced by Cargo, but I'm not sure how we can deal with multiple stability attributes without a versioning scheme to order them by. I guess that brings us back to only allowing one stability attribute per item?

> [@withoutboats](#):
>
> I'm more in favor of something similar to the conditional dependencies RFC, in which the bulk of the work is handled by cargo telling rustc which attributes to turn on / off during compilation. I'm not sure if that's workable, but I'd like it to be explored.

I looked at that RFC, but I'm not exactly sure what you mean by this. Could you explain in more detail?

> [@withoutboats](#):
>
> I also am unclear on how this interacts with the deprecated tag.

Long story short: if an item is `#[deprecated]`, it's now recognised as being unstable in addition to being recognised as deprecated (but `rustc` only warns about the item being deprecated). I agree that the text should be clearer about this.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [November 28, 2016, 10:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/10 "2016-11-28T22:52:47Z")

</div>

> [@FaultyRAM](#):
>
> I looked at that RFC, but I'm not exactly sure what you mean by this. Could you explain in more detail?

rustc has some way to be told which versions should be considered stable, and cargo passes rustc that information based on its knowledge of semver and what version this crate is.

I don't know a workable solution that allows rustc to stick to string equality matching on the `since` field, since e.g. if you have version `1.1.0`, that is "since" an infinite number of versions from `1.0.0, 1.0.1, 1.0.2...`.

I'm not really sure what the motivation is for supporting multiple stability attributes. If stability were instead a boolean state, and the "since" flag were just documentation, this wouldn't be an issue.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [November 28, 2016, 10:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/11 "2016-11-28T22:59:12Z")

</div>

A more layered solution might be this:

If cargo determines that a crate is “stable,” it passes a “stable” feature when compiling it, in which case rustc only compiles items tagged “stable.” The since flag on stable and the unstable attribute are just documentation for users.

From this basis you add cargo features to allow users of a stable crate to opt into its unstable API and warnings and such as might be appropriate.

---

<div class="post-metadata">

**Author:** ![FaultyRAM](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/faultyram/32/2645_2.png) [@FaultyRAM](https://internals.rust-lang.org/u/FaultyRAM)\
**Post date:** [November 29, 2016, 12:03am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/12 "2016-11-29T00:03:03Z")

</div>

Features are supposed to be additive, so a feature to _disable_ parts of a crate doesn’t make much sense. I like the idea of not building unstable items at all, though! I’m currently imagining something like this:

- `rustc` gains awareness of item stability. Up to one stability attribute per item, and the fields are just documentation.
- Everything that belongs to a top-level crate is built no matter what (otherwise `main()` would have to be `#[stable]`, for example).
- By default, dependencies only have their stable and unspecified items built. Rust gains a new `extern crate` attribute, `#[unstable_use]`, which is basically `#[macro_use]` but for unstable items.
- `rustc` does not gain awareness of crate stability. Instead, Cargo is responsible for ensuring that \>= `1.0.0` crates are sound (i.e. contain either no publically-visible items, or at least one publically-visible stable item; eventually unspecified items will be banned as well).

Thoughts?

---

<div class="post-metadata">

**Author:** ![dhardy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhardy/32/2399_2.png) [@dhardy](https://internals.rust-lang.org/u/dhardy)\
**Post date:** [November 29, 2016, 12:20am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/13 "2016-11-29T00:20:05Z")

</div>

> [@FaultyRAM](#):
>
> Long story short: if an item is #[deprecated], it's now recognised as being unstable in addition to being recognised as deprecated (but rustc only warns about the item being deprecated). I agree that the text should be clearer about this.

This makes sense: deprecated items are just unstable with documentation to say why (perhaps including "replaced by" or "see also"... only it might be better to do this with free-form doc than an attribute).

> [@withoutboats](#):
>
> I don't know a workable solution that allows rustc to stick to string equality matching on the since field, since e.g. if you have version 1.1.0, that is "since" an infinite number of versions from 1.0.0, 1.0.1, 1.0.2....

The other point here is that the information could be contradictory: `rustc` can't download the marked version and check it's correct. Making the field purely documentation makes it clearer that the field should be interpreted by a human.

> [@FaultyRAM](#):
>
> When compiling a stable crate, absolutely, and it should become a hard error eventually.

No it shouldn't become a hard error. This stuff comes up from time to time, and it's important: warnings are there to help humans avoid mistakes and hard errors are there to help machines avoid mistakes. Get that wrong and you start finding old code that _used to work_ just broke because of some new lint in the latest tools which tells you in effect _no you can't just run your old tried and tested code because it doesn't conform to our latest conventions_.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [November 29, 2016, 12:29am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/14 "2016-11-29T00:29:03Z")

</div>

Couple of thoughts, sorry for the scattershot reply but there's not a common thread between them.

> Features are supposed to be additive, so a feature to disable parts of a crate doesn't make much sense

By "feature" I just mean some flag for conditional compilation. Also, features can totally be used to disable compilation through `#[cfg(not())]` attributes, but that's neither here nor there because I'm imagining a more native support than 'just' using the feature system.

> Everything that belongs to a top-level crate is built no matter what (otherwise main() would have to be #[stable], for example).

If you feel that `main` needs to always be built, Rust already has an internal notion of the "main" function, and you could just always build that item. Though with `#[cfg(not())]`, you could conditionally fail to compile main today & I don't see that as an inherent problem. More importantly, I don't think this attribute should be aware of which module it is in.

I don't see why a binary would ever be compiled with the "stable only" feature activated, but I think that ties into my next comment.

> By default, dependencies only have their stable and unspecified items built.

There are a few different definitions of "by default" - what rustc does by default and what cargo does by default.

I think, by default, rustc should ignore these attributes. But rustc can accept flags which control how it interprets stable/unstable/absent attributes.

I think there are a couple of different valid default options for cargo. What you've said is one of them, but here's another (I've no strong opinion about which is better):

cargo does not pass any argument to rustc by default; by default this system is ignored. A crate's Cargo.toml, though, can have an attribute indicating that it is using stability attributes; if it has that attribute that means that when compiling it as a dependency, only stable items should be compiled (_not_ untagged items).

> Rust gains a new extern crate attribute, #[unstable\_use], which is basically #[macro\_use] but for unstable items.

I'd much rather this be an attribute you add to your declaration of that dependency in Cargo.toml, not an attribute to the extern crate declaration. But the principle is the same.

> rustc does not gain awareness of crate stability. Instead, Cargo is responsible for ensuring that \>= 1.0.0 crates are sound (i.e. contain either no publically-visible items, or at least one publically-visible stable item; eventually unspecified items will be banned as well).

I don't like this part of the RFC at all - I don't think crates should be _compelled_ to use this system. I'd much rather the situation be that crates can choose to use this system, in which untagged items are treated as unstable.

> Long story short: if an item is #[deprecated], it's now recognised as being unstable in addition to being recognised as deprecated (but rustc only warns about the item being deprecated). I agree that the text should be clearer about this.

This isn't consistent with how deprecation works in std. In std, if an item is deprecated, it is still "stable," it just emits a deprecation warning.

---

<div class="post-metadata">

**Author:** ![nixpulvis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nixpulvis/32/1233_2.png) [@nixpulvis](https://internals.rust-lang.org/u/nixpulvis)\
**Post date:** [November 18, 2017, 5:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/15 "2017-11-18T17:03:56Z")

</div>

Two thoughts jump out at me when first reading the RFC.

1. All items/crates should be implicitly unstable.
2. Replace the `unstable` attribute with `experimental`.

I really liked the experimental attribute (back when it was usable) it gives the same kind of notion of unstable, but with a little hint that it’s moving towards stability. I would think of it as a staging level of stability. This would avoid the currently confusing distinction between undefined and unstable IMO.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:27am UTC](https://internals.rust-lang.org/t/pre-rfc-crate-item-stability/4425/16 "2019-03-25T08:27:26Z")

</div>

Closed on March 25, 2019, 8:27am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
