Visibility for "this module" but not submodule?

This is something I've ran into a number of times. It may be useful or it may not even be worth considering.

I frequently have situations where I have a submodule for organization, but the submodule only contains one item (be it a trait, struct, etc.). In the parent module, I then have mod foo; pub(irrelevant) use foo::Foo;. This is fine…ordinarily. But if that parent module happens to be the crate root, then everything in the crate can still rely on the existence of the module.

Obviously I can "just" not use the full path, but that requires a conscious effort to do so. Things like autoimport in rust-analyzer default to the full path, though that's admittedly not a compiler issue. Requiring submodules to use the reëxport rather than an otherwise internal path would, in my opinion, be a net gain, as it reduces the internal coupling of the code.

Thoughts? It's quite niche.

Heh, rust-analyzer issue is interesting in that there's no clear fix here.... If we just prefer short path here, than any use in the root (or, for that matter any other module) would be preferred over original definition.

As a personal anecdata, I have stopped caring about visibility within the crate almost completely. Everything within one crate you can change easily, it's only the public API that really matters. So, in rust-analyzer we just use pub(crate) if the default visibility is not enough, and use only use crate::some::canonical::path for intra-crate uses. We do, however, run with -Dunreacheable_pub, and, in terms of impact, I wish we had that lint enabled by default (which naturally hits "pub(crate) is a mouthful to write" problem).

1 Like

Another anecdata point: I also mostly stopped caring about within-crate visibility, but I don't even use pub(crate). I usually arrange my modules into a strictly tree-like hierarchy, so that submodules don't need to use private stuff from the levels above.

2 Likes