Deprecate an implementation

I consider to deprecate this implementation in mmtkvdb (and instead provide different unit types for keys and values). However, it looks like Rust doesn't support deprecation for impls. Example:

pub trait Tr {
    fn repr(&self) -> &[u8];
}

#[deprecated]
impl Tr for () {
    fn repr(&self) -> &[u8] {
        b"\x00"
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: this `#[deprecated]` annotation has no effect
 --> src/lib.rs:5:1
  |
5 | #[deprecated]
  | ^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute
  |
  = note: `#[deny(useless_deprecated)]` on by default

error: could not compile `playground` due to previous error

What's the best way to go when you want to deprecate an impl?

1 Like

Rust doesn't provide any way of warning when a trait impl is used, so the best you can do is document it in the documentation.

2 Likes

Okay, I see. Thanks!

I found a way using associated constants to cause a custom compiler error whenever an implementation is used (which can be suppressed by requesting a crate feature then). I don't think I will use it, but want to share it nonetheless:

pub trait Tr {
    const _DEPRECATE: () = ();
    fn repr(&self) -> &[u8];
}

struct NoValue;

impl Tr for NoValue {
    fn repr(&self) -> &[u8] {
        b""
    }
}

trait DeprecateTr {}
impl DeprecateTr for () {}

impl<T: ?Sized + DeprecateTr> Tr for T {
    const _DEPRECATE: () = {
        #[cfg(not(feature = "compat"))]
        panic!("Implementation of Tr for () is deprecated. Enable feature 'compat' to suppress this error.");
    };
    fn repr(&self) -> &[u8] {
        let _ = Self::_DEPRECATE;
        b"\x00"
    }
}

fn main() {
    assert_eq!(NoValue.repr(), b"");
    
    // The following line gives a custom compile time error
    // unless the `compat` feature is used:
    
    //assert_eq!(().repr(), b"\x00");
}

(Playground)


Or a simpler version:

const fn impl_deprecated() {
    #[cfg(not(feature = "compat"))]
    panic!("Implementation of Tr for () is deprecated. Enable feature 'compat' to suppress this error.");
}

impl Tr for () {
    fn repr(&self) -> &[u8] {
        let _ = impl_deprecated();
        b"\x00"
    }
}

(Playground)

Not sure, however, if it's guaranteed that the constant doesn't get evaluated unless the trait implementation is used. But I feel like it's too hackery anyway.

2 Likes

Just FYI there's the compile_error macro for those kind of use cases.

I saw that, but it's not what helps me here:

 const fn impl_deprecated() {
     #[cfg(not(feature = "compat"))]
-    panic!("Implementation of Tr for () is deprecated. Enable feature 'compat' to suppress this error.");
+    compile_error!("Implementation of Tr for () is deprecated. Enable feature 'compat' to suppress this error.");
 }

(Playground)

This will panic even if ().repr() is never used.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.