From 8bf55cafec62d480c72bc5533fa0ebfed8e3b5b4 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 3 Jun 2015 15:56:51 +0200 Subject: [PATCH 01/17] new RFC: deprecation --- text/0000-deprecation.md | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 text/0000-deprecation.md diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md new file mode 100644 index 00000000000..ace7e7e7d24 --- /dev/null +++ b/text/0000-deprecation.md @@ -0,0 +1,42 @@ +- 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 + +# Motivation + +We want to guide the deprecation efforts to allow std to evolve freely to get the best possible API while ensuring minimum-breakage backwards compatibility for users and allow std authors to remove API items for a given version of Rust. Basically have our cake and eat it. Yum, cake. + +Of course we cannot really keep and remove a feature at the same time. To square this circle, we can follow the process outlined herein. + +# 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 absolutely 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`. [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. + +`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. + +# 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 + +# Unresolved questions + +Should we allow library writers to use the same features for deprecating their API items? From cfc7d64bfe4c60f6c061188abe4c5f7ca1636ac9 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 3 Jun 2015 16:25:21 +0200 Subject: [PATCH 02/17] word wrapped, thanks to steveklabnik --- text/0000-deprecation.md | 93 ++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 18 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index ace7e7e7d24..7a48f1d055a 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -5,38 +5,95 @@ # 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 +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. # Motivation We want to guide the deprecation efforts to allow std to evolve freely to get the best possible API while ensuring minimum-breakage backwards compatibility for users and allow std authors to remove API items for a given version of Rust. Basically have our cake and eat it. Yum, cake. -Of course we cannot really keep and remove a feature at the same time. To square this circle, we can follow the process outlined herein. +Of course we cannot really keep and remove a feature at the same time. +To square this circle, we can follow the process outlined herein. # 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 absolutely 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`. [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. - -`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. +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`. [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. + +`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. +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 +* 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? +Should we allow library writers to use the same features for +deprecating their API items? From 20666af248ab9804db1deb47bdd0964b4a73f21a Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 3 Jun 2015 16:30:39 +0200 Subject: [PATCH 03/17] clarified how cargo gets rust version --- text/0000-deprecation.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 7a48f1d055a..c7e84780a3f 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -37,7 +37,11 @@ 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`. [crates.io](https://crates.io) may deny +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 From 873f2410f4d8c562a58ffb3e04d22ef0edf06c58 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 4 Jun 2015 16:06:09 +0200 Subject: [PATCH 04/17] Added paragraph on how rustc should handle future target versions --- text/0000-deprecation.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index c7e84780a3f..e07679259bd 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -57,7 +57,11 @@ 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. +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 From 0754c8ccb7832a7e06a825657a1576d486552eaf Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 10 Jun 2015 07:17:06 +0200 Subject: [PATCH 05/17] Fleshed out the Motivation section a bit --- text/0000-deprecation.md | 61 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index e07679259bd..37b219f9658 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -5,14 +5,65 @@ # 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. +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. -# Motivation +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. -We want to guide the deprecation efforts to allow std to evolve freely to get the best possible API while ensuring minimum-breakage backwards compatibility for users and allow std authors to remove API items for a given version of Rust. Basically have our cake and eat it. Yum, cake. +# Motivation -Of course we cannot really keep and remove a feature at the same time. -To square this circle, we can follow the process outlined herein. +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) +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 From 984cc70a53d695d57bc613262ba41206676390bc Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 11 Jun 2015 23:30:35 +0200 Subject: [PATCH 06/17] added future/legacy flags to alternatives --- text/0000-deprecation.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 37b219f9658..eef3c8b6c74 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -130,6 +130,15 @@ decades, so it appears the tradeoff has seen some confirmation already. # Alternatives +* Opt-in and / or opt-out "feature-flags" (e.g. `#[legacy(..)]` for +opting out of a change) was suggested. The big problem is that this +relies on the user being able to change their dependencies, which may +not be possible for legal, organizational or other reasons. In +contrast, a defined target version doesn't ever need to change. +Depending on the specific case, it may be useful to allow a combination +of `#![legacy(..)]`, `#![future(..)]` and `#![target(..)]` where each +API version can declare the currently active feature and permit or +forbid use of the opt-in/out flags. * 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 @@ -155,4 +164,5 @@ authors to join the process # Unresolved questions Should we allow library writers to use the same features for -deprecating their API items? +deprecating their API items? I think we should at least make sure that +our design and implementation allow this in the future. From f5c7c56dc69c4a39c2605cc0b66e014f08f2fb15 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 11 Jun 2015 23:45:45 +0200 Subject: [PATCH 07/17] More explanation about security issues --- text/0000-deprecation.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index eef3c8b6c74..ac8dbd90269 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -33,16 +33,24 @@ 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. +In practice there will be some qualification, e.g. if an API is +*inherently* unsafe, it should be acceptable to remove it completely, +as any code using it was in fact broken to begin with. Therefore it is +acceptable to make this code stop working altogether. + +On the other hand, if an API permits unsafe uses, and a safer +alternative is available, we may want to *retroactively deprecate* it, +so that people will get warnings even if they specified an older target +version. We may want to have a different kind of warning than the +standard deprecation warning, as there are already some crates (e.g. +compiletest.rs) on crates.io that declare `#![deny(deprecate)]`, so +those warnings would turn to errors. + +We also 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 From 5ffff4af050424dc13d57e928b5a98a01eb5926d Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 15 Jun 2015 07:19:27 +0200 Subject: [PATCH 08/17] Clarified the paragraph about cargo/crates.io, also added Policy section --- text/0000-deprecation.md | 71 +++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index ac8dbd90269..4957eb6ddd4 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -81,32 +81,49 @@ 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). +In fact this proposal strongly advises not to remove an API type, +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. +First, crates should state their target version using a +`#![target(std= "1.2.0"]` attribute on the main module. The version +string format is the one that cargo currently uses. + +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* if the specified target version is outdated on `cargo +package` or even `cargo build --release`. To get the current rust +version, cargo could query rustc -V (with some postprocessing) or use a +symbol exported by the rust libraries (e.g. `rustc::target_version`). + +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. + +In the case of packages on crates.io, we could offer a mapping of +target versions to crate versions for each crate, so the corresponding +crate version can directly be used without further search. + +In the case of crates from git, the only reliable way to implement it +is to search the history for a suitable target version definition. Note +that we'd expect the target version to go up monotonously, so a binary +search should be possible, also we can filter out all commits that do +not touch lib.rs/mod.rs. + +This is a very complex feature to implement, so stopping with an error +and referring to the user to do the search is an acceptable option. + +[crates.io](https://crates.io) may start denying new packages that do +not declare a version to give the target version requirement more +weight to library authors. `rustc` should use this target version definition to check for deprecated items. If no target version is defined, deprecation checking @@ -129,6 +146,20 @@ 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. +## Policy + +Even if this proposal reduces breakage arising from new versions +considerably, we should still exercise some care on evolving the APIs. +We already have a `beta` and `nightly` release train representing +future versions, this should be taken into account. + +In general, the Tarzan principle should be followed where applicable +(First grab a vine, *then* let go of the previous vine). In terms of +API evolution, this means not deprecating a feature before a +replacement has been stabilized. It is still possible to deprecate a +feature in a future version, to inform users of its impending +departure. + # Drawbacks By requiring full backwards-compatibility, we will never be able to From 1b0fe8c284e45d8ad799475ff96777b7cb700722 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 15 Jun 2015 17:52:51 +0200 Subject: [PATCH 09/17] clarification on insecurity and future-proofing --- text/0000-deprecation.md | 83 +++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 4957eb6ddd4..5c8c26dfbdd 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -21,7 +21,7 @@ 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 +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) @@ -33,18 +33,20 @@ 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 an API is -*inherently* unsafe, it should be acceptable to remove it completely, -as any code using it was in fact broken to begin with. Therefore it is -acceptable to make this code stop working altogether. - -On the other hand, if an API permits unsafe uses, and a safer -alternative is available, we may want to *retroactively deprecate* it, -so that people will get warnings even if they specified an older target -version. We may want to have a different kind of warning than the +In practice there will be some qualification, e.g. if an API is +*inherently* unsafe, it should be acceptable make it completely +unavailable, as any code using it was in fact broken to begin with. +Therefore it is acceptable to make this code stop working altogether, +as long as the resulting error is not too confusing (which again means +we should make the item inaccessible instead of removing it). + +If an API permits unsafe uses, and a safer alternative is available, we +may want to mark it as insecure in addition to deprecating it, so that +people will get warnings even if they specified an older target +version. We want to have a different kind of warning than the standard deprecation warning, as there are already some crates (e.g. compiletest.rs) on crates.io that declare `#![deny(deprecate)]`, so -those warnings would turn to errors. +those warnings would turn to errors. We also really want to make features inaccessible in a newer version, not just mark them as deprecated. Otherwise we would bloat our APIs @@ -126,18 +128,35 @@ not declare a version to give the target version requirement more weight to library authors. `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. +deprecated items. If the target version is specified, 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. + +We can also define a `future deprecation` lint set to `Allow` by +default to allow people being proactive about items that are going to +be deprecated. + +Also if the target definition has a higher version than `rustc`, it +should briefly warn that it probably has to be updated in order to +build the crate. However, `rustc` should try to build the code anyway; +further errors may give the user additional information. + +If *no* target version is defined, deprecation checking is deactivated +(as we cannot assume a specific rust version), however a note +stating the same should be printed (as with cargo – we should probably +make cargo not warn on build to get rid of duplicate warnings). Since +all current code comes without a target version, we have to assume +a minimal version 1.0.0. + +In addition to the note, the `std` authors could opt to create a new +`#[since="1.2.0"]` attribute, which would allow rustc to infer the +minimal target version of some code from the API features it uses in +absence of a specified version. Deprecation warnings/errors should then +refer to the inferred target versions as well as the APIs that led to +the inference of the latest version (at least perhaps on calling +`rustc` with `-v`). `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 @@ -146,6 +165,24 @@ 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. +## Dealing with insecure items + +Since just removing insecure items, though tempting, would lead to user +confusion, a new `#[insecure(reason = "...")]` attribute should be +added to all insecure API items. An `insecure_api` lint that by default +raises `Error` can catch all uses of those items. To distinguish +between items *some uses of which* may be insecure and *inherently* +insecure items, either a second entry `inherent = true` could be added +or a `#[maybe_insecure(reason = "...")]` annotation could take the +latter part. + +The rationale for defining a separate attribute is that it avoids +mixing separate concerns (versioning and security), and that we want to +allow warnings/errors on dependencies regardless of specified target +versions. It also allows us to show the reason (from the attr) in the +lint message, which will be specific to the insecurity at hand and +hopefully be helpful to the user. + ## Policy Even if this proposal reduces breakage arising from new versions From 704c985755e587770a3b80da7574bba4355ccdb6 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 17 Jun 2015 13:28:20 +0200 Subject: [PATCH 10/17] added Cargo.toml-based target to Alternatives section --- text/0000-deprecation.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 5c8c26dfbdd..2dfef8e7c95 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -206,11 +206,19 @@ decades, so it appears the tradeoff has seen some confirmation already. # Alternatives -* Opt-in and / or opt-out "feature-flags" (e.g. `#[legacy(..)]` for -opting out of a change) was suggested. The big problem is that this -relies on the user being able to change their dependencies, which may -not be possible for legal, organizational or other reasons. In -contrast, a defined target version doesn't ever need to change. +* Have a flag in `Cargo.toml` instead of the crate root. This however +requires an argument to `rustc`, because Cargo (in addition to those +not using it) somehow has to pass it to `rustc`. Requiring such an +argument on every non-cargoized build would increase room for error and +thus pessimize usability. Also apart from availability of dependencies, +which arguably is Cargo's main raison d'être, we currently do not have +a precedent where Cargo.toml has direct effect on the working of a +crate's code. +* Opt-in and / or opt-out "feature-flags" (e.g. `#[legacy(..)]`) was +suggested. The big problem is that this relies on the user being able +to change their dependencies, which may not be possible for legal, +organizational or other reasons. In contrast, a defined target version +doesn't ever need to change. Depending on the specific case, it may be useful to allow a combination of `#![legacy(..)]`, `#![future(..)]` and `#![target(..)]` where each API version can declare the currently active feature and permit or From afb54c94785ca782d309f1e8c0e843f7f8a5e95d Mon Sep 17 00:00:00 2001 From: llogiq Date: Fri, 19 Jun 2015 18:12:04 +0200 Subject: [PATCH 11/17] Almost complete rewrite. --- text/0000-deprecation.md | 423 +++++++++++++++++++-------------------- 1 file changed, 207 insertions(+), 216 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 2dfef8e7c95..7ebcbf537f8 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -1,252 +1,243 @@ -- Feature Name: A plan for deprecating APIs within Rust +- Feature Name: Target Version - Start Date: 2015-06-03 - RFC PR: - Rust Issue: # Summary -There has been an ongoing [discussion on +This RFC proposes a small number of extensions to improve the user +experience around different rust versions, while at the same time +giving Rust developers more freedom to make changes without breaking +anyones code. + +Namely the following items: + +1. Add a `--target=`* command line argument to rustc. +This will be used for deprecation checking and for selecting code paths +in the compiler. +2. Add an (optional for now) `rust = "..."` dependency to Cargo.toml, +which `cargo new` pre-fills with the current rust version +3. Allow `std` APIs to declare an `#[insecure(level="Warn", reason="...")]` +attribute that will produce a warning or error, depending on level, +that cannot be switched off (even with `-Awarning`) +4. Add a `removed_at="..."` item to `#[deprecated]` attributes that +allows making API items unavailable starting from certain target +versions. +5. Add a number of warnings to steer users in the direction of using the +most recent Rust version that makes sense to them, while making it +easy for library writers to support a wide range of Rust versions + +## Background + +A good number of policies and mechanisms around versioning regarding +the Rust language and APIs have already been submitted, some accepted. +As a background, in no particular order: + +* [#0572 Feature gates](https://github.com/rust-lang/rfcs/blob/master/text/0572-rustc-attribute.md) +* [#1105 API Evolution](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md) +* [#1122 Language SemVer](https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md) +* [#1150 Rename Attribute](https://github.com/rust-lang/pull/1150) + +In addition, 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. +about how we are going to evolve the standard library, which this +proposal is mostly based on. -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. +Finally, the recent discussion on the first breaking change +([RFC PR #1156 Adjust default object bounds](https://github.com/rust-lang/rfcs/pull/1156)) +has made it clear that we need a more flexible way of dealing with +(breaking) changes. + +The current setup allows the `std` API to declare `#[unstable]` and +`#[deprecated]` flags, whereas users can opt-in to unstable features +with `#![feature]` flags that are customarily added to the crate root. +On usage of deprecated APIs, a warning is shown unless suppressed. +`cargo` does this for dependencies by default by calling `rustc` with +the `-Awarnings` argument. # 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) -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 an API is -*inherently* unsafe, it should be acceptable make it completely -unavailable, as any code using it was in fact broken to begin with. -Therefore it is acceptable to make this code stop working altogether, -as long as the resulting error is not too confusing (which again means -we should make the item inaccessible instead of removing it). - -If an API permits unsafe uses, and a safer alternative is available, we -may want to mark it as insecure in addition to deprecating it, so that -people will get warnings even if they specified an older target -version. We want to have a different kind of warning than the -standard deprecation warning, as there are already some crates (e.g. -compiletest.rs) on crates.io that declare `#![deny(deprecate)]`, so -those warnings would turn to errors. - -We also 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. +## 1. Language / `std` Evolution + +The following motivates items 1 and 2 (and to a lesser extent 5) + +With the current setup, we can already evolve the language and APIs, +albeit in a very limited way. For example, it is virtually impossible +to actually remove an API, because that would break code. Even minor +breaking changes (as [RFC PR #1156](https://github.com/rust-lang/rfcs/pull/1156) +cited above) generate huge discussion, because they call the general +stability of the language and environment into question. + +The problem with opt-out, as defined by +[RFC #1122](https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md) +is that code which previously compiled without problems stops working +on a Rust upgrade, and requires manual intervention to get working +again. + +This has the long-term potential of fragmenting the Rust ecosystem into +crates/projects using certain Rust versions and thus should be avoided +at some (but not all) cost. + +Note that a similar problem exists with deprecation as defined: People +may get used to deprecation warnings or just turn them off until their +build breaks. Worse, the current setup creates a mirror world for +libraries, in which deprecation doesn't exist! + +## 2. User Experience + +The following motivates items 2, 4 and 5. + +Currently, there is no way to make an API item unavailable via +deprecation. This means the API will only ever expand, with a lot of +churn (case in point, the Java language has about 20% deprecated API +surface [citation needed]). To better lead users to the right APIs and +to allow for more effective language/API evolution, this proposal adds +the `removed_at=""` item to the `#[deprecated]` attribute. + +This allows us to effectively remove an API item from a certain target +version while avoiding breaking code written for older target versions. + +Also rustc can emit better error messages than it could were the API +items actually removed. In the best case, the error messages can steer +the user to a working replacement. + +We want to avoid users setting `#[allow(deprecate)]` on their code to +get rid of the warnings. On the other hand, there have been instances +of failing builds because code was marked with `#![deny(deprecate)]`, +namely `compiletest.rs` and all crates using it. This shows that the +current system has room for improvement. + +We want to avoid failing builds because of wrong or missing target +version definition. Therefor supplying useful defaults is of the +essence. + +The documentation can be optionally reduced to items relating to the +current target version (e.g. by a switch), or deprecated items +relegated to a separate space, to reduce clutter and possible user +confusion. + +## 3. Security Considerations + +I believe that *should* a security issue in one of our APIs be found, +a swift and effective response will be required, and the current rules +make no provisions for it. Thus proposal item 3. # 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 strongly advises not to remove an API type, -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 -`#![target(std= "1.2.0"]` attribute on the main module. The version -string format is the one that cargo currently uses. - -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* if the specified target version is outdated on `cargo -package` or even `cargo build --release`. To get the current rust -version, cargo could query rustc -V (with some postprocessing) or use a -symbol exported by the rust libraries (e.g. `rustc::target_version`). - -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. - -In the case of packages on crates.io, we could offer a mapping of -target versions to crate versions for each crate, so the corresponding -crate version can directly be used without further search. - -In the case of crates from git, the only reliable way to implement it -is to search the history for a suitable target version definition. Note -that we'd expect the target version to go up monotonously, so a binary -search should be possible, also we can filter out all commits that do -not touch lib.rs/mod.rs. - -This is a very complex feature to implement, so stopping with an error -and referring to the user to do the search is an acceptable option. - -[crates.io](https://crates.io) may start denying new packages that do -not declare a version to give the target version requirement more -weight to library authors. - -`rustc` should use this target version definition to check for -deprecated items. If the target version is specified, 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. - -We can also define a `future deprecation` lint set to `Allow` by +Cargo parses the additional `rust = "..."` dependency as if it was a +library. The usual rules for version parsing apply. If no `rust` +dependency is supplied, it can either default to `*`. + +Cargo should also supply the current Rust version (which can be either +supplied by calling `rustc -V` or by linking to a rust library defining +a version object) on `cargo new`. Cargo supplies the given target +version to `rustc` via the `--target` command line argument. + +Cargo *may* also warn on `cargo package` if no `rust` version was +supplied. [crates.io](https://crates.io) *could* require a version +attribute on upload and display the required rust version on the site. + +One nice aspect of this is that `rust` looks just like yet another +dependency and effectively follows the same rules. + +`rustc` needs to accept the `--target ` command line argument. +If no argument is supplied, `rustc` defaults to its own version. The +same version syntax as Cargo applies: + +* `*` effectively means *any version*. For API items, it means +deprecation checking is disabled. For language changes, it means using +the 1.0.0 code paths (for now, we may opt to change this in the +future), because anything else would break all current code. +* `1.x` or e.g. `>=1.2.0` sets the target version to the minor version. +Deprecation checking and language code path selection occur relative +to the lowest given version. This might also affect stability handling, +though this RFC doesn't specify this as of yet. +* `1.0 - <2.0` as above, the *lowest* supplied version has to be +assumed for code path selection. However, deprecation checking should +assume the *highest* supplied version, if any. + +If the target version is *higher* than the current `rustc` version, +`rustc` should show a warning to suggest that it may need to be updated +in order to compile the crate and then try to compile the crate on a +best-effort basis. + +Optionally, we can define a `future deprecation` lint set to `Allow` by default to allow people being proactive about items that are going to -be deprecated. - -Also if the target definition has a higher version than `rustc`, it -should briefly warn that it probably has to be updated in order to -build the crate. However, `rustc` should try to build the code anyway; -further errors may give the user additional information. - -If *no* target version is defined, deprecation checking is deactivated -(as we cannot assume a specific rust version), however a note -stating the same should be printed (as with cargo – we should probably -make cargo not warn on build to get rid of duplicate warnings). Since -all current code comes without a target version, we have to assume -a minimal version 1.0.0. - -In addition to the note, the `std` authors could opt to create a new -`#[since="1.2.0"]` attribute, which would allow rustc to infer the -minimal target version of some code from the API features it uses in -absence of a specified version. Deprecation warnings/errors should then -refer to the inferred target versions as well as the APIs that led to -the inference of the latest version (at least perhaps on calling -`rustc` with `-v`). - -`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. - -## Dealing with insecure items - -Since just removing insecure items, though tempting, would lead to user -confusion, a new `#[insecure(reason = "...")]` attribute should be -added to all insecure API items. An `insecure_api` lint that by default -raises `Error` can catch all uses of those items. To distinguish -between items *some uses of which* may be insecure and *inherently* -insecure items, either a second entry `inherent = true` could be added -or a `#[maybe_insecure(reason = "...")]` annotation could take the -latter part. - -The rationale for defining a separate attribute is that it avoids -mixing separate concerns (versioning and security), and that we want to -allow warnings/errors on dependencies regardless of specified target -versions. It also allows us to show the reason (from the attr) in the -lint message, which will be specific to the insecurity at hand and -hopefully be helpful to the user. - -## Policy - -Even if this proposal reduces breakage arising from new versions -considerably, we should still exercise some care on evolving the APIs. -We already have a `beta` and `nightly` release train representing -future versions, this should be taken into account. - -In general, the Tarzan principle should be followed where applicable -(First grab a vine, *then* let go of the previous vine). In terms of -API evolution, this means not deprecating a feature before a -replacement has been stabilized. It is still possible to deprecate a -feature in a future version, to inform users of its impending -departure. +be deprecated. + +`rustc` should also show a warning or error, depending on level, on +encountering usage of API items marked as `#[insecure]`. The attribute +has two values: + +* `level` can either be `Warning` or `Error` and default to `Error` +* `reason` contains a description on why usage of this item was deemed + a security risk. This attribute is mandatory. + +While `rustdoc` already parses the deprecation flags, it should in +addition relegate items removed in the current version to a separate +area below the other documentation and optically mark them as removed. +We should not completely remove them, because that would confuse users +who see the API items in code written for older target versions. + +Also, `rustdoc` should show if API items are marked with `#[insecure]`, +including displaying the `reason` prominently. + +# Optional Extension: Legacy flags + +The `#[deprecated]` attribute could get an optional `legacy="xy` +entry, which could effectively group a set of APIs under the given +name. Users can then declare the `#[legacy]` flag as defined in +[RFC #1122](https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md) +to specifically allow usage of the grouped APIs, thus selectively +removing the deprecation warning. + +This would create a nice feature parity between language code paths and +`std` API deprecation checking. # 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. +bloat. However, the cost of maintaining the outdated APIs is far +outweighted by the benefits. Case in point: Other successful languages +have lived with this for multiple decades, so it appears the tradeoff +has seen some confirmation already. + +Cargo and `rustc` need some code to manage the additional rules. I +estimate the effort to be reasonably low. # Alternatives -* Have a flag in `Cargo.toml` instead of the crate root. This however -requires an argument to `rustc`, because Cargo (in addition to those -not using it) somehow has to pass it to `rustc`. Requiring such an -argument on every non-cargoized build would increase room for error and -thus pessimize usability. Also apart from availability of dependencies, -which arguably is Cargo's main raison d'être, we currently do not have -a precedent where Cargo.toml has direct effect on the working of a -crate's code. -* Opt-in and / or opt-out "feature-flags" (e.g. `#[legacy(..)]`) was -suggested. The big problem is that this relies on the user being able +* It was suggested that opt-in and opt-out (e.g. by `#[legacy(..)]`) +could be sufficient to work around any breaking code on API or language +changes. The big problem here is that this relies on the user being able to change their dependencies, which may not be possible for legal, organizational or other reasons. In contrast, a defined target version -doesn't ever need to change. +doesn't ever need to change + Depending on the specific case, it may be useful to allow a combination -of `#![legacy(..)]`, `#![future(..)]` and `#![target(..)]` where each -API version can declare the currently active feature and permit or -forbid use of the opt-in/out flags. +of `#![legacy(..)]`, `#![feature(..)]` and the target version where +each Rust version can declare the currently active feature set and +permit or forbid use of the opt-in/out flags + * 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 +date or face breakage. The risk of breaking existing code makes this +strategy very unattractive + +* 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 +needing a new attribute key. # Unresolved questions -Should we allow library writers to use the same features for -deprecating their API items? I think we should at least make sure that -our design and implementation allow this in the future. +I no longer have any. Please join the discussion to add yours. From 045c03e207fec06dca38bf3e220ebe523c01fc92 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 25 Jun 2015 09:45:14 +0200 Subject: [PATCH 12/17] Renamed --target to --target-version, reworded Cargo entry default --- text/0000-deprecation.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 7ebcbf537f8..11bb3156c8c 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -12,14 +12,15 @@ anyones code. Namely the following items: -1. Add a `--target=`* command line argument to rustc. +1. Add a `--target-version=`* command line argument to rustc. This will be used for deprecation checking and for selecting code paths in the compiler. 2. Add an (optional for now) `rust = "..."` dependency to Cargo.toml, which `cargo new` pre-fills with the current rust version -3. Allow `std` APIs to declare an `#[insecure(level="Warn", reason="...")]` -attribute that will produce a warning or error, depending on level, -that cannot be switched off (even with `-Awarning`) +3. Allow `std` APIs to declare an +`#[insecure(level="Warn", reason="...")]` attribute that will produce +a warning or error, depending on level, that cannot be switched off +(even with `-Awarning`) 4. Add a `removed_at="..."` item to `#[deprecated]` attributes that allows making API items unavailable starting from certain target versions. @@ -126,12 +127,12 @@ make no provisions for it. Thus proposal item 3. Cargo parses the additional `rust = "..."` dependency as if it was a library. The usual rules for version parsing apply. If no `rust` -dependency is supplied, it can either default to `*`. +dependency is supplied, it defaults to `*`. Cargo should also supply the current Rust version (which can be either supplied by calling `rustc -V` or by linking to a rust library defining a version object) on `cargo new`. Cargo supplies the given target -version to `rustc` via the `--target` command line argument. +version to `rustc` via the `--target-version` command line argument. Cargo *may* also warn on `cargo package` if no `rust` version was supplied. [crates.io](https://crates.io) *could* require a version @@ -140,9 +141,9 @@ attribute on upload and display the required rust version on the site. One nice aspect of this is that `rust` looks just like yet another dependency and effectively follows the same rules. -`rustc` needs to accept the `--target ` command line argument. -If no argument is supplied, `rustc` defaults to its own version. The -same version syntax as Cargo applies: +`rustc` needs to accept the `--target-version ` command line +argument. If no argument is supplied, `rustc` defaults to its own +version. The same version syntax as Cargo applies: * `*` effectively means *any version*. For API items, it means deprecation checking is disabled. For language changes, it means using From 2e44ed0d547293f7d49576690c7628794f090aff Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 25 Jun 2015 23:58:46 +0200 Subject: [PATCH 13/17] added open question about cargo and detailed design about feature flag integration --- text/0000-deprecation.md | 41 ++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 11bb3156c8c..5b5138a3b67 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -12,11 +12,12 @@ anyones code. Namely the following items: -1. Add a `--target-version=`* command line argument to rustc. -This will be used for deprecation checking and for selecting code paths -in the compiler. +1. Add a `--target-version=`** command line argument to +rustc. This will be used for deprecation checking and for selecting +code paths in the compiler. 2. Add an (optional for now) `rust = "..."` dependency to Cargo.toml, -which `cargo new` pre-fills with the current rust version +which `cargo new` pre-fills with the current rust version +(alternatively this could be a package attribute) 3. Allow `std` APIs to declare an `#[insecure(level="Warn", reason="...")]` attribute that will produce a warning or error, depending on level, that cannot be switched off @@ -24,8 +25,8 @@ a warning or error, depending on level, that cannot be switched off 4. Add a `removed_at="..."` item to `#[deprecated]` attributes that allows making API items unavailable starting from certain target versions. -5. Add a number of warnings to steer users in the direction of using the -most recent Rust version that makes sense to them, while making it +5. Add a number of warnings to steer users in the direction of using +the most recent Rust version that makes sense to them, while making it easy for library writers to support a wide range of Rust versions ## Background @@ -39,8 +40,8 @@ As a background, in no particular order: * [#1122 Language SemVer](https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md) * [#1150 Rename Attribute](https://github.com/rust-lang/pull/1150) -In addition, there has been an ongoing [discussion on -internals](https://internals.rust-lang.org/t/thoughts-on-aggressive-deprecation-in-libstd/2176/55) +In addition, 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, which this proposal is mostly based on. @@ -90,10 +91,13 @@ The following motivates items 2, 4 and 5. Currently, there is no way to make an API item unavailable via deprecation. This means the API will only ever expand, with a lot of -churn (case in point, the Java language has about 20% deprecated API -surface [citation needed]). To better lead users to the right APIs and -to allow for more effective language/API evolution, this proposal adds -the `removed_at=""` item to the `#[deprecated]` attribute. +churn (case in point, the Java language as of Version 8 lists 462 +deprecated constructs, including methods, constants and complete +classes, in relation to 4241 classes, this makes for about 10% of +deprecated API surface. Note that this is but a rough estimate). To +better lead users to the right APIs and to allow for more effective +language/API evolution, this proposal adds the `removed_at=""` +item to the `#[deprecated]` attribute. This allows us to effectively remove an API item from a certain target version while avoiding breaking code written for older target versions. @@ -104,7 +108,7 @@ the user to a working replacement. We want to avoid users setting `#[allow(deprecate)]` on their code to get rid of the warnings. On the other hand, there have been instances -of failing builds because code was marked with `#![deny(deprecate)]`, +of failing builds because code was marked with `#![deny(warnings)]`, namely `compiletest.rs` and all crates using it. This shows that the current system has room for improvement. @@ -147,7 +151,7 @@ version. The same version syntax as Cargo applies: * `*` effectively means *any version*. For API items, it means deprecation checking is disabled. For language changes, it means using -the 1.0.0 code paths (for now, we may opt to change this in the +the `1.0.0` code paths (for now, we may opt to change this in the future), because anything else would break all current code. * `1.x` or e.g. `>=1.2.0` sets the target version to the minor version. Deprecation checking and language code path selection occur relative @@ -166,6 +170,11 @@ Optionally, we can define a `future deprecation` lint set to `Allow` by default to allow people being proactive about items that are going to be deprecated. +`rustc` should resolve the `#[feature]` flags against the upper bound +of the specified target version instead the current version, but +default to the current version if no target version is specified or the +specified version has no upper bound. + `rustc` should also show a warning or error, depending on level, on encountering usage of API items marked as `#[insecure]`. The attribute has two values: @@ -185,7 +194,7 @@ including displaying the `reason` prominently. # Optional Extension: Legacy flags -The `#[deprecated]` attribute could get an optional `legacy="xy` +The `#[deprecated]` attribute could get an optional `legacy="xy"` entry, which could effectively group a set of APIs under the given name. Users can then declare the `#[legacy]` flag as defined in [RFC #1122](https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md) @@ -241,4 +250,4 @@ needing a new attribute key. # Unresolved questions -I no longer have any. Please join the discussion to add yours. +Should the rust = "" be a *dependency* or a package attribute? From 97b32e8e95eaa25bcd37a7ce327d63b82c56333a Mon Sep 17 00:00:00 2001 From: llogiq Date: Fri, 26 Jun 2015 23:42:12 +0200 Subject: [PATCH 14/17] made 'rust' a package attribute instead of a pseudo-dependency --- text/0000-deprecation.md | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 5b5138a3b67..cdd3e05bd58 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -15,19 +15,21 @@ Namely the following items: 1. Add a `--target-version=`** command line argument to rustc. This will be used for deprecation checking and for selecting code paths in the compiler. -2. Add an (optional for now) `rust = "..."` dependency to Cargo.toml, -which `cargo new` pre-fills with the current rust version -(alternatively this could be a package attribute) +2. Add an optional `rust = "..."` package attribute to Cargo.toml, +which `cargo new` pre-fills with the current rust version. 3. Allow `std` APIs to declare an `#[insecure(level="Warn", reason="...")]` attribute that will produce a warning or error, depending on level, that cannot be switched off (even with `-Awarning`) 4. Add a `removed_at="..."` item to `#[deprecated]` attributes that allows making API items unavailable starting from certain target -versions. +versions. 5. Add a number of warnings to steer users in the direction of using the most recent Rust version that makes sense to them, while making it easy for library writers to support a wide range of Rust versions +6. (optional) add a `legacy="..."` item to `#[deprecated]` attributes +that allows grouping API items under a legacy flag that is already +defined in RFC #1122 (see below) ## Background @@ -129,9 +131,9 @@ make no provisions for it. Thus proposal item 3. # Detailed design -Cargo parses the additional `rust = "..."` dependency as if it was a -library. The usual rules for version parsing apply. If no `rust` -dependency is supplied, it defaults to `*`. +Cargo parses the additional `rust = "..."` package attribute. The usual +rules for version parsing apply. If no `rust` attribute is supplied, it +defaults to `*`. Cargo should also supply the current Rust version (which can be either supplied by calling `rustc -V` or by linking to a rust library defining @@ -139,11 +141,12 @@ a version object) on `cargo new`. Cargo supplies the given target version to `rustc` via the `--target-version` command line argument. Cargo *may* also warn on `cargo package` if no `rust` version was -supplied. [crates.io](https://crates.io) *could* require a version -attribute on upload and display the required rust version on the site. +supplied. A few versions in the future, Cargo could also warn of +missing version attributes on build or other actions, at least if the +crate is a library. -One nice aspect of this is that `rust` looks just like yet another -dependency and effectively follows the same rules. +[crates.io](https://crates.io) *could* require a version attribute on +upload and display the required rust version on the site. `rustc` needs to accept the `--target-version ` command line argument. If no argument is supplied, `rustc` defaults to its own @@ -202,7 +205,9 @@ to specifically allow usage of the grouped APIs, thus selectively removing the deprecation warning. This would create a nice feature parity between language code paths and -`std` API deprecation checking. +`std` API deprecation checking. Also it would lessen the pain for users +who want to upgrade their systems one feature at a time and can use the +legacy flags to effectively manage their usage of deprecated items. # Drawbacks @@ -250,4 +255,4 @@ needing a new attribute key. # Unresolved questions -Should the rust = "" be a *dependency* or a package attribute? +None From 62bda96d2d65c0d91f92ae96f35756588954af03 Mon Sep 17 00:00:00 2001 From: llogiq Date: Sun, 28 Jun 2015 22:54:07 +0200 Subject: [PATCH 15/17] formatting improvements --- text/0000-deprecation.md | 85 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index cdd3e05bd58..62d8964df39 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -13,23 +13,23 @@ anyones code. Namely the following items: 1. Add a `--target-version=`** command line argument to -rustc. This will be used for deprecation checking and for selecting -code paths in the compiler. + rustc. This will be used for deprecation checking and for selecting + code paths in the compiler. 2. Add an optional `rust = "..."` package attribute to Cargo.toml, -which `cargo new` pre-fills with the current rust version. + which `cargo new` pre-fills with the current rust version. 3. Allow `std` APIs to declare an -`#[insecure(level="Warn", reason="...")]` attribute that will produce -a warning or error, depending on level, that cannot be switched off -(even with `-Awarning`) + `#[insecure(level="Warn", reason="...")]` attribute that will + produce a warning or error, depending on level, that cannot be + switched off (even with `-Awarning`) 4. Add a `removed_at="..."` item to `#[deprecated]` attributes that -allows making API items unavailable starting from certain target -versions. + allows making API items unavailable starting from certain target + versions. 5. Add a number of warnings to steer users in the direction of using -the most recent Rust version that makes sense to them, while making it -easy for library writers to support a wide range of Rust versions + the most recent Rust version that makes sense to them, while making + it easy for library writers to support a wide range of Rust versions 6. (optional) add a `legacy="..."` item to `#[deprecated]` attributes -that allows grouping API items under a legacy flag that is already -defined in RFC #1122 (see below) + that allows grouping API items under a legacy flag that is already + defined in RFC #1122 (see below) ## Background @@ -153,16 +153,16 @@ argument. If no argument is supplied, `rustc` defaults to its own version. The same version syntax as Cargo applies: * `*` effectively means *any version*. For API items, it means -deprecation checking is disabled. For language changes, it means using -the `1.0.0` code paths (for now, we may opt to change this in the -future), because anything else would break all current code. -* `1.x` or e.g. `>=1.2.0` sets the target version to the minor version. -Deprecation checking and language code path selection occur relative -to the lowest given version. This might also affect stability handling, -though this RFC doesn't specify this as of yet. + deprecation checking is disabled. For language changes, it means + using the `1.0.0` code paths (for now, we may opt to change this in + the future), because anything else would break all current code. +* `1.x` or e.g. `>=1.2.0` sets the target version to the minor version. + Deprecation checking and language code path selection occur relative + to the lowest given version. This might also affect stability + handling, though this RFC doesn't specify this as of yet. * `1.0 - <2.0` as above, the *lowest* supplied version has to be -assumed for code path selection. However, deprecation checking should -assume the *highest* supplied version, if any. + assumed for code path selection. However, deprecation checking should + assume the *highest* supplied version, if any. If the target version is *higher* than the current `rustc` version, `rustc` should show a warning to suggest that it may need to be updated @@ -224,34 +224,35 @@ estimate the effort to be reasonably low. # Alternatives * It was suggested that opt-in and opt-out (e.g. by `#[legacy(..)]`) -could be sufficient to work around any breaking code on API or language -changes. The big problem here is that this relies on the user being able -to change their dependencies, which may not be possible for legal, -organizational or other reasons. In contrast, a defined target version -doesn't ever need to change + could be sufficient to work around any breaking code on API or + language changes. The big problem here is that this relies on the + user being able to change their dependencies, which may not be + possible for legal, organizational or other reasons. In contrast, a + defined target version doesn't ever need to change -Depending on the specific case, it may be useful to allow a combination -of `#![legacy(..)]`, `#![feature(..)]` and the target version where -each Rust version can declare the currently active feature set and -permit or forbid use of the opt-in/out flags + Depending on the specific case, it may be useful to allow a + combination of `#![legacy(..)]`, `#![feature(..)]` and the target + version where each Rust version can declare the currently active + feature set and permit or forbid use of the opt-in/out flags * 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. The risk of breaking existing code makes this -strategy very unattractive + 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. The risk of breaking existing code makes + this strategy very unattractive * 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 + 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. + 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. # Unresolved questions From b8f14903745fe8ce8ddc95fa64ef8252eea989b9 Mon Sep 17 00:00:00 2001 From: llogiq Date: Sat, 4 Jul 2015 13:25:14 +0200 Subject: [PATCH 16/17] Added previous proposal to alternatives, added bikeshedding to unresolved questions --- text/0000-deprecation.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 62d8964df39..67e6bbfaa13 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -223,6 +223,14 @@ estimate the effort to be reasonably low. # Alternatives +* An earlier version of this proposal suggested using a crate attribute + instead of a cargo package attribute and a compiler option, to also + allow cargo-less use cases without manual interaction. However it was + determined that those cases usually target the current Rust version + anyway, and the current proposal allows us to default to the current + version for rustc, while the earlier proposal would have defaulted to + 1.0.0 by necessity of not breaking existing code + * It was suggested that opt-in and opt-out (e.g. by `#[legacy(..)]`) could be sufficient to work around any breaking code on API or language changes. The big problem here is that this relies on the @@ -252,8 +260,10 @@ estimate the effort to be reasonably low. 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. + requiring a new attribute key # Unresolved questions -None +The names for the cargo package attribute and the rustc compiler option +are still subject to bikeshedding (however, discussion has stalled, +suggesting the current names are good enough). From 955430b84c835368f25f37c3ad9295719a6bd377 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 9 Jul 2015 07:12:51 +0200 Subject: [PATCH 17/17] #[insecure]-flagging removed from RFC, added some open questions (as prompted by @alexcrichton) --- text/0000-deprecation.md | 59 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/text/0000-deprecation.md b/text/0000-deprecation.md index 67e6bbfaa13..d04ef3698db 100644 --- a/text/0000-deprecation.md +++ b/text/0000-deprecation.md @@ -17,17 +17,13 @@ Namely the following items: code paths in the compiler. 2. Add an optional `rust = "..."` package attribute to Cargo.toml, which `cargo new` pre-fills with the current rust version. -3. Allow `std` APIs to declare an - `#[insecure(level="Warn", reason="...")]` attribute that will - produce a warning or error, depending on level, that cannot be - switched off (even with `-Awarning`) -4. Add a `removed_at="..."` item to `#[deprecated]` attributes that +3. Add a `removed_at="..."` item to `#[deprecated]` attributes that allows making API items unavailable starting from certain target versions. -5. Add a number of warnings to steer users in the direction of using +4. Add a number of warnings to steer users in the direction of using the most recent Rust version that makes sense to them, while making it easy for library writers to support a wide range of Rust versions -6. (optional) add a `legacy="..."` item to `#[deprecated]` attributes +5. (optional) add a `legacy="..."` item to `#[deprecated]` attributes that allows grouping API items under a legacy flag that is already defined in RFC #1122 (see below) @@ -45,7 +41,7 @@ As a background, in no particular order: In addition, 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, which this -proposal is mostly based on. +proposal is somewhat based on. Finally, the recent discussion on the first breaking change ([RFC PR #1156 Adjust default object bounds](https://github.com/rust-lang/rfcs/pull/1156)) @@ -63,7 +59,7 @@ the `-Awarnings` argument. ## 1. Language / `std` Evolution -The following motivates items 1 and 2 (and to a lesser extent 5) +The following motivates items 1 and 2 (and to a lesser extent 4) With the current setup, we can already evolve the language and APIs, albeit in a very limited way. For example, it is virtually impossible @@ -89,7 +85,7 @@ libraries, in which deprecation doesn't exist! ## 2. User Experience -The following motivates items 2, 4 and 5. +The following motivates items 2, 3 and 4. Currently, there is no way to make an API item unavailable via deprecation. This means the API will only ever expand, with a lot of @@ -123,12 +119,6 @@ current target version (e.g. by a switch), or deprecated items relegated to a separate space, to reduce clutter and possible user confusion. -## 3. Security Considerations - -I believe that *should* a security issue in one of our APIs be found, -a swift and effective response will be required, and the current rules -make no provisions for it. Thus proposal item 3. - # Detailed design Cargo parses the additional `rust = "..."` package attribute. The usual @@ -178,23 +168,12 @@ of the specified target version instead the current version, but default to the current version if no target version is specified or the specified version has no upper bound. -`rustc` should also show a warning or error, depending on level, on -encountering usage of API items marked as `#[insecure]`. The attribute -has two values: - -* `level` can either be `Warning` or `Error` and default to `Error` -* `reason` contains a description on why usage of this item was deemed - a security risk. This attribute is mandatory. - While `rustdoc` already parses the deprecation flags, it should in addition relegate items removed in the current version to a separate area below the other documentation and optically mark them as removed. We should not completely remove them, because that would confuse users who see the API items in code written for older target versions. -Also, `rustdoc` should show if API items are marked with `#[insecure]`, -including displaying the `reason` prominently. - # Optional Extension: Legacy flags The `#[deprecated]` attribute could get an optional `legacy="xy"` @@ -219,7 +198,11 @@ have lived with this for multiple decades, so it appears the tradeoff has seen some confirmation already. Cargo and `rustc` need some code to manage the additional rules. I -estimate the effort to be reasonably low. +estimate the effort to be reasonably low. For *compiler changes* +however, unless it's a genuine bug and unless there could be programs +relying on the old behaviours, both the old and new code paths have to +be maintained in the compiler, which is the biggest cost of +implementing this RFC. # Alternatives @@ -264,6 +247,20 @@ estimate the effort to be reasonably low. # Unresolved questions -The names for the cargo package attribute and the rustc compiler option -are still subject to bikeshedding (however, discussion has stalled, -suggesting the current names are good enough). +* The names for the cargo package attribute and the rustc compiler + option are still subject to bikeshedding (however, discussion has + stalled, suggesting the current names are good enough). + +* How do we determine if something is a genuine bug (and should be + changed retroactively)? + +* If we agree that something needs to be changed retroactively (i.e. in + older versions), do we also release the old versions anew? Which + ones? Should we nominate LTS versions? Who would maintain them? + +* Is *forward-compatibility* sufficiently handled? Seeing that e.g. + adding an item to a trait could break code using that trait, changing + a trait would require both versions being interoperable, which could + be impossible in the general case. This would needed to be handled by + finding a new name for the trait or supplying a default + implementation.