Revisiting Rust’s modules, part 2

First, I agree with the deprecation of "extern crate" in favor of discovering the crates from Cargo.toml.

I didn't see anything in the proposals to address the biggest problem I've encountered with the module system: If some module a does impl b::T for S, and I want to call a method on a::S declared in b::T, I have to use b::T, even if I never actually reference the name b::T. I find this to be a much more significant ergonomic issue than what's been discussed so far, because it isn't just a stumbling block for learning Rust, but rather a persistent problem. (See Inconvenience of using functions defined in traits, an ugly workaround, and proposed solution for previous discussion of this issue.)

I agree with this. Everything should continue to be private by default. Controlling what gets exported from a module is a big part of ensuring that the module's API is safe and maintainable. One of the main reasons for splitting a crate into multiple submodules is to minimize the coupling between the different parts of the module, largely by taking advantage of the current private-by-default design.

I agree with this sentiment. At a minimum, I think the proposed mechanism should take into consideration the Cargo.toml include = [ ... ] and exclude = [ ... ] so that only files included in the crate are actually considered. I think this would address most of the concerns regarding problems caused by “implicitness” since those same kinds of problems are similar to the concerns of accidentally including files in a crate's published package.

I find browsing Rust projects to be annoying due to the large number of subdirectories under src/ and the large number of files named "mod.rs". I also think the current situation where we have to move x.rs to x/mod.rs when we add submodule x::y in x/y.rs to be unfortunate; I think we should be able to keep x.rs as-is while adding x/y.rs. I use #[path] on mod declarations to work around this now; if/when we get rid of mod then we should fix fix this annoyance since there would be no place to put #[path] in that case.

I don't think pub use is a great replacement for mod. pub use isn't intuitive at all as it does two things: it brings the item into the current scope and exports it from the current scope. IMO, even if we had implicitly discovered submodules, pub mod would be clearer than pub use. However, I think declaring submodules with mod is not a large burden and neither is it confusing, so I think retaining mandatory mod declarations is fine; the declarations enhance readability, IMO.

So, basically, I think getting rid of extern crate seems like a clear win, whereas I would be happy to skip the rest of the proposed changes, especially if that would free up resources for fixing other issues that persist after the initial learning curve.

7 Likes