Hidden trait implementation

I'm looking for a way to mark types as being compatible with my public API without exposing the implementation of the traits. How would I setup the visibility such that this would compile:

mod library {    
    struct Value;

    trait Trait {
        fn unstable_method(&self);
    }
    
    impl Trait for Value {
        fn unstable_method(&self) {
            panic!("How dare ye");
        }
    }
    
    fn needy<T>(v: T) where T: Trait {}
}

fn generic_wrapper<T: library::Trait>(v: T) {
    library::needy(v);
}
fn main() {
    library::needy(library::Value);
    generic_wrapper(library::Value);
}

but this would error:

fn generic_wrapper<T: library::Trait>(v: T) {
    T::unstable_method();
}

I'm imagining something that mirrors the sealed trait pattern, but I can't quite get it to work

1 Like

You can use a sealed trait pattern:

// in library a

// this is for ergonomics within the crate, not necessary
pub(crate) use seal::Seal;

// this will prevent accidentally leaking `Seal`
// seal cannot be named outside your crate, so
// no one else can implement `Seal`.
#[forbid(missing_docs)]
mod seal {
    pub trait Seal {}
}

pub trait PrivateTrait: Seal {
    fn unstable_method(&self) {
        panic!("How dare ye");
    }
}

pub fn needy<T>(v: T) where T: Trait {}
// in bin

fn generic_wrapper<T: library_a::PrivateTrait>(v: T) {
    library::needy(v);
}

If you don't want to expose unstable_method, then put it on Seal instead of PrivateTrait. We still have PrivateTrait to that we can use it as a bound in generic_wrapper, and Seal prevents outside implementations. Seal is explicitly not documented, so if we accidentally do something like pub use seal::Seal; or something, we get a hard compile error that can't be turned off.

Note: the sealed trait pattern does allow you to call unstable_method from outside the crate. You can prevent this using a private token: like so. By combining the sealed trait pattern with private tokens, you can create traits that can only be implemented in your crate, and contain methods that can only be called in your trait.

2 Likes

crossposted to reddit: https://www.reddit.com/r/rust/comments/g6q08b/hidden_trait_implementation/

You mentioned on reddit that you want to be able to hide associated types, this isn't possible with traits. The best you can do is the sealed trait pattern. Yes, others will still be able to access those associated types, but there isn't a way to prevent that.

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