-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Target Version #1147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Target Version #1147
Changes from 6 commits
8bf55ca
cfc7d64
20666af
fb16b8a
873f241
0754c8c
984cc70
f5c7c56
5ffff4a
1b0fe8c
704c985
afb54c9
045c03e
2e44ed0
97b32e8
62bda96
b8f1490
d1e2725
955430b
22108ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| 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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| 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? | ||
There was a problem hiding this comment.
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.