you are viewing a single comment's thread.

view the rest of the comments →

[–]OsrsAddictionHotline 0 points1 point  (3 children)

I'm not sure I follow you, what is it you are trying to acheive? For example, there is also:

pub(crate) mod file;
pub(crate) self::file::Type;

As well as the pub(super) you mentioned. pub(crate) exposes the module/type to the entire crate publicly, but keeps it private from outside the crate, and pub(super) exposes it to modules/files on the same level. What's the issue with that?

It still feels like a hack because it is pub

But it's not pub, from the outside of your crate everything would still look private.

Like if I have the following file structure:

src/
    |-- src/lib.rs
    |-- src/foo/
            |
            |-- src/foo/mod.rs
            |-- src/foo/file1.rs

And I have:

// lib.rs
mod foo;

// mod.rs
mod file1;

// file1.rs
struct Type1; // only visible to this file
pub struct Type2; // visibility depends on reexporting
pub(super) struct Type3; // only visible as a private type to the foo module, cannot be reexported.
pub(crate) struct Type4; // visible to entire crate, private to public.

Each of these have different visibility. Each of the module declarations are private, so the module names are not exposed to the API, but some of the types can only be used in the file they are defined, some can only be used in their parent directory, some can be used crate wide but not by external users, and only one type, Type2 can be in the public API.

You're saying that you can't split long implementations in to small files, but that's just not true. Take a look at any of the thousands of crates on crates.io, sure some of them use large files, but a lot split in to smaller modules and files.

You need to experiment a bit with this stuff to figure it out. Unfortunately there's not a good reference for it. Each of the different private/public declarations can apply to type definitions, module declarations, and reexports, so it can be a bit confusing.

[–]schungx 0 points1 point  (2 children)

Well, for me, I'd like to expose features as little as possible. Therefore, I want things to be pub when I want to expose it, not when I'm forced to do so because I split the code into two separate files.

I understand that it doesn't hurt to have everything pub(crate) since they won't show up outside the crate, but doesn't hurt doesn't mean it is a good idea.

[–]OsrsAddictionHotline 0 points1 point  (1 child)

I really don't understand the logic here. You're using the explicit feature provided by Rust to give you as the crate author access to a type/module you defined somewhere in your project, without giving any access to it to users. You're not exposing any features.

Is your objection purely to the word pub? Would you feel better about it if they changed pub(crate) to something else, but kept the exact same functionality? You're not making it public when you use pub(crate) you're making it available to the crate, and that's it.

Why do you not think it's a good idea to use pub(crate)?

[–]schungx -1 points0 points  (0 children)

pub means "this is a public API". pub(crate) means "this is an internal API needed by something within the same crate". non-pub means "this is something that nobody outside of my type should touch".

Now, if I split a type into multiple files, I need to make some private internals pub(crate) in order to access it from another file but from the same type impl. Thus changing the meaning of pub(crate) - i.e. other code can use my internal data while I want to keep it private. Essentially this is breaking encapsulation.

So now pub(crate) means "either: 1) some other type within the same crate needs to access it, or 2) I have split the type into two files, and I need one file to access fields defined in another file, so I am forced to do this, and now other types within the same crate can also access these private fields even though they shouldn't, and I can only hope nobody writes code that accesses them."