Skip to content

Commit

Permalink
relegated use to alternatives, user story, clippy
Browse files Browse the repository at this point in the history
  • Loading branch information
llogiq committed Nov 19, 2015
1 parent c8a726c commit 8ec2ccd
Showing 1 changed file with 58 additions and 38 deletions.
96 changes: 58 additions & 38 deletions text/0000-deprecation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
# Summary

This RFC proposes to allow library authors to use a `#[deprecated]` attribute,
with optional `since = "`*version*`"`, `reason = "`*free text*`"` and
`use = "`*substitute declaration*`"` fields. The compiler can then
warn on deprecated items, while `rustdoc` can document their deprecation
accordingly.
with optional `since = "`*version*`"` and `reason = "`*free text*`"`fields. The
compiler can then warn on deprecated items, while `rustdoc` can document their
deprecation accordingly.

# Motivation

Expand All @@ -30,39 +29,29 @@ fields and enum variants) can be given a `#[deprecated]` attribute. All
possible fields are optional:

* `since` is defined to contain the version of the crate at the time of
deprecating the item, following the semver scheme. It makes no sense to put a
version number higher than the current newest version here, and this is not
checked (but could be by external lints, e.g.
[rust-clippy](https://github.com/Manishearth/rust-clippy).
deprecating the item, following the semver scheme. Rustc does not know about
versions, thus the content of this field is not checked (but will be by external
lints, e.g. [rust-clippy](https://github.com/Manishearth/rust-clippy).
* `reason` should contain a human-readable string outlining the reason for
deprecating the item. While this field is not required, library authors are
strongly advised to make use of it to convey the reason for the deprecation to
users of their library. The string is interpreted as plain unformatted text
(for now) so that rustdoc can include it in the item's documentation without
messing up the formatting.
* `use`, if included, must be the import path (or a semicolon-delimited list of
paths) to a set of API items that will replace the functionality of the
deprecated item. All crates in scope can be reached by this path. E.g. let's
say my `foo()` item was superceded by either the `bar()` or `baz()` functions
in the `bar` crate, in conjunction with the `bruzz(_)` function in the `baz`
crate, I can `#[deprecate(use="bar::{bar,baz};baz::bruzz")] foo()`, as long
as I have the `bar` and `baz` crates in the library path. Rustc checks if the
item is actually available, otherwise returning an error.

On use of a *deprecated* item, `rustc` will `warn` of the deprecation. Note
that during Cargo builds, warnings on dependencies get silenced. Note that
while this has the upside of keeping things tidy, it has a downside when it
comes to deprecation:
that during Cargo builds, warnings on dependencies get silenced. While this has
the upside of keeping things tidy, it has a downside when it comes to
deprecation:

Let's say I have my `llogiq` crate that depends on `foobar` which uses a
deprecated item of `serde`. I will never get the warning about this unless I
try to build `foobar` directly. We may want to create a service like `crater`
to warn on use of deprecated items in library crates, however this is outside
the scope of this RFC.

`rustdoc` will show deprecation on items, with a `[deprecated]`
box that may optionally show the version, reason and/or link to the replacement
if available.
`rustdoc` will show deprecation on items, with a `[deprecated]` box that may
optionally show the version and reason where available.

The language reference will be extended to describe this feature as outlined
in this RFC. Authors shall be advised to leave their users enough time to react
Expand All @@ -71,38 +60,69 @@ before *removing* a deprecated item.
The internally used feature can either be subsumed by this or possibly renamed
to avoid a name clash.

# Intended Use

Crate author Anna wants to evolve her crate's API. She has found that one
type, `Foo`, has a better implementation in the `rust-foo` crate. Also she has
written a `frob(Foo)` function to replace the earlier `Foo::frobnicate(self)`
method.

So Anna first bumps the version of her crate (because deprecation is always
done on a version change) from `0.1.1` to `0.2.1`. She also adds the following
prefix to the `Foo` type:

```
extern crate rust_foo;
#[deprecated(since = "0.2.1", use="rust_foo::Foo",
reason="The rust_foo version is more advanced, and this crates' will likely be discontinued")]
struct Foo { .. }
```

Users of her crate will see the following once they `cargo update` and `build`:

```
src/foo_use.rs:27:5: 27:8 warning: Foo is marked deprecated as of version 0.2.1
src/foo_use.rs:27:5: 27:8 note: The rust_foo version is more advanced, and this crates' will likely be discontinued
```

Rust-clippy will likely gain more sophisticated checks for deprecation:

* `future_deprecation` will warn on items marked as deprecated, but with a
version lower than their crates', while `current_deprecation` will warn only on
those items marked as deprecated where the version is equal or lower to the
crates' one.
* `deprecation_syntax` will check that the `since` field really contains a
semver number and not some random string.

Clippy users can then activate the clippy checks and deactivate the standard
deprecation checks.

# Drawbacks

* The required checks for the `since` and `use` fields are potentially
quite complex.
* Once the feature is public, we can no longer change its design

# Alternatives

* Do nothing
* make the `since` field required and check that it's a single version
* Optionally the deprecation lint could check the current version as set by
cargo in the CARGO_CRATE_VERSION environment variable (the rust build process
should set this environment variable, too). This would allow future
deprecations to be shown in the docs early, but not warned against by the
stability lint (there could however be a `future-deprecation` lint that should
be `Allow` by default)
* require either `reason` or `use` be present
* `reason` could include markdown formatting
* The `use` could simply be plain text, which would remove much of the
complexity here
* The `use` field could be left out and added later. However, this would
lead people to describe a replacement in the `reason` field, as is already
happening in the case of rustc-private deprecation
* rename the `reason` field to `note` to clarify it's broader usage.
* add a `note` field and make `reason` a field with specific meaning, perhaps
even predefine a number of valid reason strings, as JEP277 currently does
* Add a `use` field containing a plain text of what to use instead
* Add a `use` field containing a path to some function, type, etc. to replace
the current feature. Currently with the rustc-private feature, people are
describing a replacement in the `reason` field, which is clearly not the
original intention of the field
* Optionally, `cargo` could offer a new dependency category: "doc-dependencies"
which are used to pull in other crates' documentations to link them (this is
obviously not only relevant to deprecation).
obviously not only relevant to deprecation)

# Unresolved questions

* What other restrictions should we introduce now to avoid being bound to a
possibly flawed design?
* How should the multiple values in the `use` field work? Just split by
comma or some other delimiter?
* Can / Should the `std` library make use of the `#[deprecated]` extensions?
* Bikeshedding: Are the names good enough?

0 comments on commit 8ec2ccd

Please sign in to comment.