Avoid expose types to public

I have a public trait called Foo, and a secret type SecretFoo which is not public. I want to all my functions return a Arc<dyn Foo> without exposing SecretFoo, but when I wrote something complicated, I don't know to do it (hide the SecretFoo):

pub trait Foo {}

struct SecretFoo {}
impl Foo for SecretFoo {}

pub trait Bar {
    type Foo;
}

pub struct Baz {}
impl Bar for Baz {
    type Foo = Arc<dyn Foo>;
}

pub fn test<T: Bar>() -> T::Foo {
    Arc::new(SecretFoo {})
}

This will not compile because compiler don't know how to convert Arc<SecretFoo> to T::Foo:

error[E0308]: mismatched types
  --> src/main.rs:21:5
   |
20 | pub fn test<T: Bar>() -> T::Foo {
   |                          ------ expected `<T as Bar>::Foo` because of return type
21 |     Arc::new(SecretFoo {})
   |     ^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found struct `Arc`
   |
   = note: expected associated type `<T as Bar>::Foo`
                       found struct `Arc<SecretFoo>`
help: consider constraining the associated type `<T as Bar>::Foo` to `Arc<SecretFoo>`
   |
20 | pub fn test<T: Bar<Foo = Arc<SecretFoo>>>() -> T::Foo {
   |                   ++++++++++++++++++++++

I don't want to follow the suggestion from the compiler, because it will expose the SecretFoo to the public, any other way to do this?

P.S. Currently, I can leave my SecretFoo to private but using the suggestion, but the compiler will warn me:

warning: private type `SecretFoo` in public interface (error E0446)
  --> src/main.rs:20:1
   |
20 | pub fn test<T: Bar<Foo = Arc<SecretFoo>>>() -> T::Foo {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
   = note: `#[warn(private_in_public)]` on by default

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 0.63s
Process finished with exit code 0

P.P.S: It indeed not necessary to make SecretFoo as private, I can leave it to the public, but I don't want the user who use my crate get confused with too many types that he doesn't need to know at all.

Sounds like you need type_alias_impl_trait feature: Rust Playground

Why don't you just specify Arc<dyn Foo> as the return type directly?

Also, the current design can't work anyway, since anyone can implement Bar with any type they want as Bar::Foo. So fn test<T: Bar>(t: T) -> T::Foo can't work unless you can access a value of T::Foo through a value of type T (via Bar).

2 Likes

Good point, I somehow know what the problem is, I need a constraint to make sure that any Foo type in Bar should be able to convert to Arc<dyn Foo>. Let me try.

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.