Is it possible to hide the bound of a generic type parameter?

TL; DR: I am trying to hide implementation details of a generic type. When using it, I don't need to know what are the bound of that type:

// This function doesn't need to know what trait T implements
pub fn usage<T: WhateverImplementationDetails>(wrapper: &Wrapper<T>) {
    wrapper.nice_public_function();
}

I would like much more to be able to just write something like (pseudo Rust)

pub fn usage(wrapper: &Wrapper<_>) {
    wrapper.nice_public_function();
}

Note: if Wrapper itself was a trait, I could have used any of those syntax, effectively hiding that there is an impl<T> Wrapper for WhateverImplementationDetails<T>.

pub fn usage<T: Wrapper>(wrapper: &T);
pub fn usagewrapper(& impl Wrapper);
pub fn usagewrapper(& dyn Wrapper);

This pattern can be really useful for wrapper class over a trait, since the wrapped trait isn't visible at all from the public interface of the wrapper, and it's guaranteed that to be able to compile, the caller of the function will implement use a type that implement that trait for the generic parameter of the wrapper.

// used only internally by the methods of `Wrapper<T: WhateverImplementationDetails>`
trait WhateverImplementationDetails {
    fn foo();
    fn bar();
}

// The public wrapper ...
pub struct Wrapper<T: WhateverImplementationDetails>{
    forward: WhateverImplementationDetails;
}

// ... and the public API that the wrapper exposes
impl<T: WhateverImplementationDetails> Wrapper<T> {
    // no public methods exposes `WhateverImplementationDetails`
    pub fn nice_public_function(&self) {
        // uses WhateverImplementationDetails only internally
        self.forward.foo();
        self.forward.bar();
    }
}

// This function doesn't need to know what trait T implements, but AFAIK Rust syntax requires to write it
pub fn usage<T: WhateverImplementationDetails>(wrapper: &Wrapper<T>) {
    wrapper.nice_public_function();
}

pub struct WhateverImplementationDetailsImpl; // nice name btw!
impl WhateverImplementationDetails for WhateverImplementationDetailsImpl { /* ... */ }
const SPECIFIC_IMPLEMENTATION: Wrapper<WhateverImplementationDetailsImpl> = Wrapper{ forward: WhateverImplementationDetails};

pub fn main() {
    // At call site, it's guaranteed that the trait will be implemented for the generic parameter,
    // otherwise it could not compile
    usage(&SPECIFIC_IMPLEMENTATION);
}

No. You can use trait objects (dyn Trait) or you can rename the trait to have a better name, optionally through a trait like this:

trait MyPublicTrait: MyTraitImpl { }
2 Likes

This is something that will be allowed eventually by the Implied Bounds RFC. However, making that work within the existing trait system ends up being super complicated, so I believe it's currently blocked on integrating the new type solving system, chalk, with rustc. As a plus, chalk already handles implied bounds, so we should get them automatically once integration is completed and stabilized.

As @alice said, there's no good way to do this today. And it's not likely to happen (or be stabilized) for a while, as chalk integration itself still has a ton of work to do.

1 Like

It's what I was expecting, and it's nice to see that some work is already being done.

2 Likes

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