mb-lang
mb-lang

Reputation: 93

Rust libraries: Visibility of types vs. ability to name said types

I have a Rust workspace with a library and a binary that uses said library:

In the library, I was lazy and did not care about distinguishing pub from pub(crate). I thought I could fix this by only exporting the symbols a user would need via pub use:

Despite foo::Foo not being public, publicly exporting baz is allowed, which surprised me. I was even more surprised that using the returned object in the binary is actually possible:

Now, I already know how to prevent this from happening: Distinguish pub from pub(crate) everywhere in my library.

However, I still have a few questions:

Upvotes: 1

Views: 92

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71380

Why is this allowed?

Because pub items are exported. Period.

If part of their path is not exported (one of the modules they're inside), then they are unnamable (you cannot name them), but they still can be used if they're inferred, or if there is another way to name them (someone pub uses them).

If the crate type of "lib" is "dylib", will all public symbols be exported, regardless of whether they are in a non-public module? Or only those symbols which are exposed "indirectly", as in my example?

A simple test shows it is exported.

Does the unintuitive state of lib::foo::Foo (public type that is part of the API/ABI, but cannot be named) have any practical purpose?

Yes, the more common being sealing a trait.

If you want to have a trait which can be used but cannot be implemented, the most common way to do that is:

mod private {
    pub trait Sealed {}
    impl Sealed for MyType {}
}

pub trait MyTrait: private::Sealed { ... }
impl MyTrait for MyType { ... }

This way, the trait and its members can be used, but it cannot be implemented because it has private::Sealed as a supertrait so you need to implement it too, but you cannot do that because it is unnamable.

Upvotes: 3

Related Questions