Skip to content
Closed
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8bf55ca
new RFC: deprecation
llogiq Jun 3, 2015
cfc7d64
word wrapped, thanks to steveklabnik
llogiq Jun 3, 2015
20666af
clarified how cargo gets rust version
llogiq Jun 3, 2015
fb16b8a
Merge branch 'master' of https://github.com/rust-lang/rfcs
llogiq Jun 4, 2015
873f241
Added paragraph on how rustc should handle future target versions
llogiq Jun 4, 2015
0754c8c
Fleshed out the Motivation section a bit
llogiq Jun 10, 2015
984cc70
added future/legacy flags to alternatives
llogiq Jun 11, 2015
f5c7c56
More explanation about security issues
llogiq Jun 11, 2015
5ffff4a
Clarified the paragraph about cargo/crates.io, also added Policy section
llogiq Jun 15, 2015
1b0fe8c
clarification on insecurity and future-proofing
llogiq Jun 15, 2015
704c985
added Cargo.toml-based target to Alternatives section
llogiq Jun 17, 2015
afb54c9
Almost complete rewrite.
llogiq Jun 19, 2015
045c03e
Renamed --target to --target-version, reworded Cargo entry default
llogiq Jun 25, 2015
2e44ed0
added open question about cargo and detailed design about feature fla…
llogiq Jun 25, 2015
97b32e8
made 'rust' a package attribute instead of a pseudo-dependency
llogiq Jun 26, 2015
62bda96
formatting improvements
llogiq Jun 28, 2015
b8f1490
Added previous proposal to alternatives, added bikeshedding to unreso…
llogiq Jul 4, 2015
d1e2725
Merge branch 'master' of https://github.com/rust-lang/rfcs
llogiq Jul 4, 2015
955430b
#[insecure]-flagging removed from RFC, added some open questions (as …
llogiq Jul 9, 2015
22108ae
Merge branch 'master' of https://github.com/rust-lang/rfcs
llogiq Jul 9, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions text/0000-deprecation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
- Feature Name: A plan for deprecating APIs within Rust
- Start Date: 2015-06-03
- RFC PR:
- Rust Issue:

# Summary

There has been an ongoing [discussion on
internals](https://internals.rust-lang.org/t/thoughts-on-aggressive-deprecation-in-libstd/2176/55)
about how we are going to evolve the standard library. This RFC tries
to condense the consensus.

As a starting point, the current deprecation feature allows a developer
to annotate their API items with `#[deprecated(since="1.1.0")]` and
have suitable warnings shown if the feature is used.

# Motivation

We want to:

1. evolve the `std` API, including making items unavailable with new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely agree that we want to evolve the APIs that libstd provides, but I'm not quite in agreement that we want to remove deprecated APIs. I think that the overhead of keeping around unstable APIs is unlikely to become too burdensome, but this is of course tough to predict. I also think that it's possible to leave these APIs around without confusing new users through various mitigation tactics like compiler error messages, documentation, etc.

versions
2. with minimal -- next to no -- breakage
3. be able to plug security/safety holes
4. avoid confusing users
5. stay backwards-compatible so people can continue to use dependencies
written for older versions (except where point 3. forbids this)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also somewhat skeptical that we'd outright remove an API because it's unsafe or insecure, for example gets is still in the C standard library, it's just plastered with endless warnings to not use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gets was actually removed from the standard in C11, though I think most stdlibs still ship it: http://en.wikipedia.org/wiki/C11_%28C_standard_revision%29#Changes_from_C99.

6. give users sensible defaults
7. and an update plan when they want to use a more current version

This was quite short, so let me explain a bit: We want Rust to be
successful, and since the 1.0.0 release, there is an expectation of
stability. Therefore the first order of business when evolving the
`std` API is: **Don't break people's code**.

In practice there will be some qualification, e.g. if fixing a security
hole requires breaking an API, it is nonetheless acceptable, because
the API was broken to begin with, as is code using it. So breaking this
code is acceptable.

On the other hand, we really want to make features inaccessible in a
newer version, not just mark them as deprecated. Otherwise we would
bloat our APIs with deprecated features that no one uses (see Java). To
do this, it's not enough to hide the feature from the docs, as that
would be confusing (see point 4.) to those who encounter a hidden API.

Not breaking code also mean we do not want to have the deprecation
feature interfere with a project's dependencies, which would teach
people to disable or ignore the warnings until their builds break. On
the other hand, we don't want to have all unavailable APIs show up
for library writers, as that -- apart from defeating the purpose of the
deprecation feature -- would create a confusing mirror world,
which is directly in conflict to point 4.

We also want the feature to be *usable* to the programmer, therefore
any additional code we require should be minimal. If the feature is too
obscure, or too complicated to use, people will just
`#![allow(deprecate)]` and complain when their build finally breaks.

Note that we expect many more *users* than *writers* of the `std` APIs,
so the wants of the former should count higher than those of the latter.

Ideally, this can be done so that all parts play well together: Cargo
could help with setup (and possibly reporting), rustc warnings / error
reporting should be extended to inform people of pending or active
deprecations, rustdoc needs some way of reflecting the API lifecycle.

# Detailed design

We already declare deprecation in terms of Rust versions (like "1.0",
"1.2"). The current attribute looks like `#[deprecated(since = "1.0.0",
reason="foo")]`. This should be extended to add an optional
`removed_at` key, to state that the item should be made inaccessible at
that version. Note that while this allows for marking items as
deprecated, there is purposely no provision to actually *remove* items.
In fact this proposal bans removing an API type outright, unless
security concerns are deemed more important than the resulting breakage
from removing it or the API item has some fault that means it cannot be
used correctly at all (thus leaving the API in place would result in
the same level of breakage than removing it).

Currently every rustc version implements only its own version, having
multiple versions is possible using something like multirust, though
this does not work within a build. Also currently rustc versions do not
guarantee interoperability. This RFC aims to change this situation.

First, crates should state their target version using a `#![version =
"1.0.0"]` attribute. Cargo should insert the current rust version by
default on `cargo new` and *warn* if no version is defined on all other
commands. It may optionally *note* that the specified target version is
outdated on `cargo package`. To get the current rust version, cargo
could query rustc -V (with some postprocessing) or use some as yet
undefined symbol exported by the rust libraries.

[crates.io](https://crates.io) may deny
packages that do not declare a version to give the target version
requirement more weight to library authors. Cargo should also be able
to hold back a new library version if its declared target version is
newer than the rust version installed on the system. In those cases,
cargo should emit a warning urging the user to upgrade their rust
installation.

`rustc` should use this target version definition to check for
deprecated items. If no target version is defined, deprecation checking
is deactivated (as we cannot assume a specific rust version), however a
warning stating the same should be issued (as with cargo – we should
probably make cargo not warn on build to get rid of duplicate
warnings). Otherwise, use of API items whose `since` attribute is less
or equal to the target version of the crate should trigger a warning,
while API items whose `removed_at` attribute is less or equal to the
target version should trigger an error.

Also if the target definition has a higher version than `rustc`, it
should warn that it probably has to be updated in order to build the
crate.

`rustdoc` should mark deprecated APIs as such (e.g. make them in a
lighter gray font) and relegate removed APIs to a section below all
others (and that may be hidden via a checkbox). We should not
completely remove the documentation, as users of libraries that target
old versions may still have a use for them, but neither should we let
them clutter the docs.

# Drawbacks

By requiring full backwards-compatibility, we will never be able to
actually remove stuff from the APIs, which will probably lead to some
bloat. Other successful languages have lived with this for multiple
decades, so it appears the tradeoff has seen some confirmation already.

# Alternatives

* Follow a more agressive strategy that actually removes stuff from the
API. This would make it easier for the libstd creators at some cost for
library and application writers, as they are required to keep up to
date or face breakage * Hide deprecated items in the docs: This could
be done either by putting them into a linked extra page or by adding a
"show deprecated" checkbox that may be default be checked or not,
depending on who you ask. This will however confuse people, who see the
deprecated APIs in some code, but cannot find them in the docs anymore
* Allow to distinguish "soft" and "hard" deprecation, so that an API
can be marked as "soft" deprecated to dissuade new uses before hard
deprecation is decided. Allowing people to specify deprecation in
future version appears to have much of the same benefits without
needing a new attribute key. * Decide deprecation on a per-case basis.
This is what we do now. The proposal just adds a well-defined process
to it * Never deprecate anything. Evolve the API by adding stuff only.
Rust would be crushed by the weight of its own cruft before 2.0 even
has a chance to land. Users will be uncertain which APIs to use * We
could extend the deprecation feature to cover libraries. As Cargo.toml
already defines the target versions of dependencies (unless declared as
`"*"`), we could use much of the same machinery to allow library
authors to join the process

# Unresolved questions

Should we allow library writers to use the same features for
deprecating their API items?