Multiple re-exports in crate

What are the arguments against re-exporting an item multiple times in a crate?

I assume it can get a little annoying that the same item appears multiple times when you search for it. But are there any other reasons?

The std itself is auto "re-exported" in each and every mod you declare, so it genuinely depends.

What kinds of items are we talking about? struct, enum, fn's? If you have a bunch of items you keep referring to again and again: is there anything that's stopping you from declaring a common.rs in root src beside main.rs with a handful of pub use ...; to be able to use crate::common::*; in every other place, instead of re-exporting them one by one each time?

Right, I should have made it clear what the point of it is: Someone posted a PSA a few years ago discouraging (re-)exporting items more than once in a crate. From the context, I'm pretty sure it was relating to rustdoc, but I couldn't find the post again so I'm not 100% sure.

In my specific case it's basically a pretty massive crate, which (among other things) pulls in another pretty huge crate and re-exports it in a submodule.

foo-types is a crate that exists to collect a bunch of types (several hundreds, mixed structs, enums, fns and also some traits). foo-client-lib is the one end-users will actually use. Everything in foo-types is reexported from foo-client-lib under types. (i.e. the end user shouldn't really need to know that foo-types exists, they just use foo-client-lib). However, foo-client-lib is - as I said - massive. It has a bunch of other submodules, relating to what subsystems they interact with. A developer is likely only interested in one, or a few, of them. Each submodule contains functions that take in and return types that are highly specific to it (but that are really defined in foo-types), and there are a lot of conversion trait implementations for many of the types.

The reason I'm thinking about re-exporting twice is that I still want to continue to re-export foo-types under foo-client-lib::types (everything collected in one place, for those who want it). But I also want to re-export (for instance) all the logging-related types in foo-client-lib::logging as well. This is purely so that developers who are only interested in a single subsystem can easily get an overview of all the types that concerns them in the documentation, but I also want it to be possible to get the "all the types in one page" overview that the foo-client-lib::types provides.

That's an interesting concern, actually. I'd love to hear from different folks with different (kinds of) crates and/or libraries published already, as I tend to keep my projects to myself (for the time being) - what works best for whom, why they chose that particular project structure, etc.

Personally: I'd be most grateful to any lib's author if they went out of their way to clearly separate and document the items concerning one particular set and/or aspect of lib's functionality from the rest of it. The only thing I'd rather avoid dealing with is aliasing with type A = B; and pub use X as Y; for no good reason. Plain re-exports themselves of the pub use LibStruct/Enum/Trait; kind? Keep 'em coming. As long as it's all clear and consistent, - thumbs up from me.

Just don't forget to annotate the mod itself towards the beginning, explaining in general terms that these particular exports are all about. Not sure what sort of PSA you were referring to, but if I had to guess its arguments would most likely revolve around "re-duplication is bad" and "never repeat yourself". Every great rule has a generous amount of exceptions standing right next to it.

1 Like