# Adding \`what\` parameter to #\[deprecated\]

**URL:** <https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451>\
**Category:** language design\
**Created:** [November 25, 2020, 10:37pm UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451 "2020-11-25T22:37:03Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [November 25, 2020, 10:37pm UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/1 "2020-11-25T22:37:04Z")

</div>

## Abstract

it'd be nice to be able to specify what exactly is deprecated as opposed to deprecating all instances of an item. It could be done by supplying `what = "value"` where value could be:

- `impl` - implementation of this trait or trait method is deprecated but calling the method or using trait in bounds is fine
- `call` - calling this trait method is deprecated but implementing it is fine
- `bound` - using this trait in bounds is deprecated

## Use cases

### Error trait

`std::error::Error` has `cause` deprecated as it got replaced by `source` However `source` is not present in old version of `std`. So a crate that intends to support old versions of Rust has to call `cause` and get a warning in the new versions of Rust. (This is a real case in the `slog` crate.)

This situation is not ideal because calling `cause()` should be perfectly fine. It just forwards to `source`. implementing `cause()` is problematic without `source()` and redundant if `source` is present. Thus it'd make more sense to only warn when `cause()` is being implemented, not when it's called.

Using `#[deprecated(what = "impl")]` on `cause()` would tell the compiler that implementing the method is deprecated but would not lead to warnings if `cause()` is called.

### From/Into

Since `From` implies `Into`, types implementing `Into` are superset of types implementing `From` As a result, it makes more sense to implement `From` and bound by `Into` or call `into()`. These attributes could warn users about this being the case:

```rust
#[deprecated(what = "bound")]
trait From<T> {
    // I think what = "bound" should imply deprecated what = "call" on each trait method
    // But for illustration purposes I wrote it explicitly
    #[deprecated(what = "call")]
    fn from(val: T) -> Self;
}

#[deprecated(what = "impl")]
trait Into<T> {
    fn into(self) -> T;
}

#[allow(deprecated)]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> T {
        T::from(self)
    }
}

```

This would remind people to do the right thing.

### Low level and high-level methods

Consider a hypothetical trait:

```rust
trait Foo {
    #[deprecated(description = "use high_level instead" what = "call")]
    fn low_level(&mut self);
    // #[deprecated(what = "impl")] intentionally not used because allowing specialization is useful
    fn high_level(&mut self) {
        // do some other logic

        // #[allow(deprecated)] could be implicit in this specific case
        self.low_level()
        // perhaps more logic
    }
}

```

This would help people understand the meaning of the methods better. One example of a trait like this is `std::io::Read` however I'd not sugggest to add it to that one since raw `read()` is still widely used. OTOH, maybe actually warning newbies about it is a good thing and slapping `#[allow(deprecated)] to mean "I know read is not guaranteed to read whole buffer" may be fine. That being said this debate is out of scope of my post. For now.

### Helper marker traits

[`arse_arg`](https://docs.rs/parse_arg) has two similar traits: `ParseArg` and `ParseArgFromStr`. `ParseArgFromStr` requires `FromStr` and implies `ParseArg`. This API makes it possible to implement `ParseArg` for `PathBuf` (without causing issues with encoding) while not burdening implementors of `ParseArg` too much if the type already implements `FromStr`. A similar approach is used in `embedded-hal`.

A downside of this is there's a risk that someone will misunderstand the purpose of those traits and bound by `ParseArgFromStr` by accident. Adding `#[deprecated(what = "bound")]` to `ParseArgFromStr` would help mitigating this risk.

## What do you think?

Is it worth the effort to do RFC for this? Do you see any problems with this idea?

---

<div class="post-metadata">

**Author:** ![sfackler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sfackler/32/9_2.png) [@sfackler](https://internals.rust-lang.org/u/sfackler)\
**Post date:** [November 26, 2020, 2:08am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/2 "2020-11-26T02:08:58Z")

</div>

> [@Kixunil](#):
>
> Using `#[deprecated(what = "impl")]` on `cause()` would tell the compiler that implementing the method is deprecated but would not lead to warnings if `cause()` is called.

But we _do_ want to deprecate calls to `cause()` and have people use `source()` instead!

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [November 26, 2020, 2:35am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/3 "2020-11-26T02:35:14Z")

</div>

I strongly prefer the current behavior of deprecated. We are trying to gently push everything towards nondeprecated things. The intermediate remedy of sprinkling `#[allow(deprecated)]`'s around the project is not awful, but could be better. I believe I have seen a proposal on here for some wider scoped allow deprecated with a target, which also sounds fine and covers your case.

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [November 26, 2020, 9:14am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/4 "2020-11-26T09:14:27Z")

</div>

@sfackler do you expect Rust 2.0 to come out anytime soon? Because if not, I don't see a good reason to deprecate calls to `cause()`.

Anyway, that's just one of the use cases. Another crate could have a different policy than `std` so the feature can be useful for other crates even if it doesn't end up in `std`.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [November 26, 2020, 11:04am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/5 "2020-11-26T11:04:24Z")

</div>

> [@Kixunil](#):
>
> @sfackler do you expect Rust 2.0 to come out anytime soon?

No, it may very well never happen.

> [@Kixunil](#):
>
> Because if not, I don't see a good reason to deprecate calls to `cause()` .

Deprecation doesn't necessarily mean that it will be removed. Many deprecation's are because something is replaced with a better alternative ([`try!`](https://doc.rust-lang.org/stable/std/macro.try.html) is replaced with `?`), is easy to misuse ([`mem::uninitialized`](https://doc.rust-lang.org/stable/std/mem/fn.uninitialized.html) was often used in ways introducing UB), or is unsound ([`CommandExt::before_exec`](https://doc.rust-lang.org/stable/std/os/unix/process/trait.CommandExt.html#method.before_exec) is missing `unsafe`, so has been deprecated in favor of `pre_exec` which is `unsafe`) In all cases, we can't remove them due to the stability guarantee.

In the case of `cause()` vs `source()`, `cause()` simply couldn't be used for some of it's intended purpose as it was missing `+ 'static`. Not deprecating it could easily confuse someone trying to use `cause()` when they need to use `source()`.

---

<div class="post-metadata">

**Author:** ![sfackler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sfackler/32/9_2.png) [@sfackler](https://internals.rust-lang.org/u/sfackler)\
**Post date:** [November 26, 2020, 12:15pm UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/6 "2020-11-26T12:15:43Z")

</div>

> [@Kixunil](#):
>
> do you expect Rust 2.0 to come out anytime soon? Because if not, I don't see a good reason to deprecate calls to `cause()` .

The entire point of deprecation is to avoid needing a breaking API change to get people to stop using something.

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [November 28, 2020, 10:20pm UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/7 "2020-11-28T22:20:47Z")

</div>

> Not deprecating it could easily confuse someone trying to use `cause()` when they need to use `source()` .

Interesting point of view. Wouldn't that mean that it could be reasonable to deprecate `Rc` because people might be confused and they really need `Arc`? 😉

I think `cause()` still may have its place for people who don't need down casting. And FTR, downcasting may be one day implemented for non-`'static` types.

> The entire point of deprecation is to avoid needing a breaking API change to get people to stop using something.

AFAIK it's formally breaking even if you don't know of anyone using it. And I think it's not unreasonable to use `cause()` if you're dealing with an old code or some interesting policy requiring older (certified?) version of the language.

Anyway, we're still talking about this one thing. What do you think of the other use cases?

---

<div class="post-metadata">

**Author:** ![mjbshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjbshaw/32/5103_2.png) [@mjbshaw](https://internals.rust-lang.org/u/mjbshaw)\
**Post date:** [November 29, 2020, 12:50am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/8 "2020-11-29T00:50:13Z")

</div>

> [@bjorn3](#):
>
> > [@Kixunil](#):
> >
> > @sfackler do you expect Rust 2.0 to come out anytime soon?
> 
> No, it may very well never happen.

Isn't Rust 2018 basically Rust 2.0? If not, then what do people mean by "Rust 2.0"?

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [November 29, 2020, 3:20am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/9 "2020-11-29T03:20:08Z")

</div>

Rust 2.0 would allow major breaking changes, like removing `mpsc` from std or changing the signature of `Write::write` to allow uninitialized buffers. Things that will never be done on an edition change.

---

<div class="post-metadata">

**Author:** ![mjbshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjbshaw/32/5103_2.png) [@mjbshaw](https://internals.rust-lang.org/u/mjbshaw)\
**Post date:** [November 30, 2020, 5:41am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/10 "2020-11-30T05:41:25Z")

</div>

So that's really std 2.0, right? "Rust" means many things, and Rust 2018 already introduced breaking syntactical changes. So we already have a "Rust language 2.0". Just not a "rustc 2.0" or a "core/std 2.0".

"Rust" is used as an umbrella term for many things, so thank you for clarifying the specific usage here.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [November 30, 2020, 9:59am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/11 "2020-11-30T09:59:39Z")

</div>

Rust 2018 only introduced breaking syntactical changes. It doesn't change anything to the core language. Almost all differences are gone at HIR level. Rust 2018 has the same semantics as Rust 2015. It only presents them in a somewhat different syntax. This is the reason that Rust 2015 and Rust 2018 crates can be used interchangeably. As the only changes are syntactical and not semantical, I wouldn't call it "Rust language 2.0". I would rather call it something like "Rust syntax 2.0".

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [December 10, 2020, 9:05am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/12 "2020-12-10T09:05:04Z")

</div>

Rust and `std` are so deeply connected that they share the same version number. I guess they could be a bit disconnected so that e.g. new std features would be usable in old Rust compiler but that's a different discussion.

So by Rust 2.0 I mean big breakage, not edition. As explained by others, editions can't remove methods from traits.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 10, 2020, 10:04am UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/13 "2020-12-10T10:04:03Z")

</div>

`source()` is intended to be a complete replacement for `cause()`. There's no "use this if you need this, use that if you need that". The old method had a bug in its signature, and this is the fix. There's only one supported method now.

`Arc` is not a bug fix of `Rc`, but a different type with different use-case. They're meant to coexist, unlike `cause()` and `source()`.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [December 10, 2020, 3:43pm UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/14 "2020-12-10T15:43:15Z")

</div>

> [@Kixunil](#):
>
> Rust and `std` are so deeply connected that they share the same version number. I guess they could be a bit disconnected

No they can't be. `std` has special handling in `rustc`, using features that are tied to the specific release.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 10, 2021, 3:43pm UTC](https://internals.rust-lang.org/t/adding-what-parameter-to-deprecated/13451/15 "2021-03-10T15:43:19Z")

</div>

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