Revisiting Rust's modules


Imports from submodules are not nearly as common in practice as imports from ancestor modules.


But it would remove one of the major confusions with the module system and make it consistent with how module-qualified names work. And all for a minimal price of two characters in absolute paths.

And it would be trivially implementable.


I disagree that that the ugliness is a minimal price, and it’s not backwards compatible anyway.


Yes, backwards compatibility is an issue. But the premise was, that relative paths are not implementable, not that they are not backwards compatible.

But I also disagree on ugliness. For me, ergonomics is does not mean less characters to type. Ergonomics for me means having a consistent model without special rules for special cases. That way I can think faster and I will gladly type a few more characters.

In that specific case, I also like the analogy to relative path file systems. Modules would correspond to directories (in fact exactly as in your proposal).

I think much of the confusion comes from the difference to how (relative) paths usually work and matching that expectation would be an ergonomic win IMO.


I don’t have a proposal!

I don’t care that much what we do, as long as we don’t try to do relative imports with items from parent modules in scope, because that is unimplementable. I wouldn’t like having to write e.g. use ::std::fs::File everywhere, but I wouldn’t stand in the way if the entire community were united in favor of it, I guess.


Oh, I confused you with aturon. Sorry about that!

And I totally agree with that. I didn’t even think that relative could be meant like this until you posted the example.


Then ergonomic initiative 2.0 will remove these two characters again in 2022 as a boilerplate and papercut, with people :confetti_ball:-ing about writing less symbols and a few grumpy old men still nagging about consistent models and special cases.

I wonder how many of “ergonomic” features approved now will end up as “major confusions” in five years.


So that’s what “relative imports” meant. I guess I was lucky it was before my time.


I don’t think I can share this observation just yet. I think most modules would be not inline/anonymous.

What about adding inline mod syntax, without letting docs lean towards one way or another, and then letting people use it, and then in a year, evaluating how the distribution between old and new syntax is in new crates?


I guess I’m unsure why a backwards compatible, incremental improvement that seems relatively uncontroversial would be discarded in favor of something that’s not backwards compatible, not incremental and controversial?

I guess I’m confused. It honestly seems like this is a waste of time, cause I’m proposing things that you considered and rejected on the path to the proposal, but it wasn’t documented that it was considered and why it was rejected.


@ahmedcharles I don’t think that this tone will really help us to attain our shared goal.


It seems reasonable to give someone feedback that they shouldn’t leave details out because it causes confusion and wastes time.


“Rejected” is too strong a word about that proposal; it may well be that some variant of it is the right way to go!

In other words, what @withoutboats said doesn’t mean “and hence we’d never consider that” but rather “and hence we ended up proposing this alternative”. But now the rationale has been spelled out, and we can dig into it further, as @est31 is.

Keep in mind that there’s limited time to write up ideas, let alone discuss all of them in a community-wide setting. On the way to a proposal, one generally throws many away. It’s just not possible for everyone to know everything that’s been discussed.


I like inline mod for these reasons. I proposed use extern along those lines - a modifier keyword that fixes common complain, and looks and behaves naturally.

With these two we would have backward compatible solution to some of the pains listed in, that doesn’t change things too much, but gets rid of some common boilerplate/redundancy, gets rid (supersedes) of extern crate leaving us with just two concepts: mod and use.


mod and extern crate are similar, in that they add new ‘items’ into scope and give the current crate access to things that it didn’t have access to before. use is purely about name resolution. For that reason, I think the confusion between mod, extern crate and use is purely one of education rather than language design. Rust is always going to have crates, modules and a way to create short bindings to access ‘distant’ names. This is why I don’t think that a simplification is possible and we should focus on education rather than some language fix that just hides things.

Removing extern crate would be unfortunate, since I like the redundancy of having a source code reference to external dependencies rather than only a reference in the build system. For people who want to ignore dependencies, I’d be fine with cargo new adding a directive to Cargo.toml which would pass command line options to rustc which cause dependencies in Cargo.toml to not require extern crate. That means that people using rustc independently get to pick which they want, both being explicit to them. And cargo users can remove the directive from their Cargo.toml trivially and new users get a new default behavior that let’s them ignore dependency complications for a little longer.

I think combining the use syntax with semantics that don’t simply rename items that are already accessible via a different name would make things more complex and harder to teach.

And as somewhat of an aside: I think someone mentioned that foo/ is confusing as a beginner. I suppose that makes sense but why would a beginner be writing code which benefits from having items that are basically crate_name::mod1::mod2::item. If you’re writing code that benefits from that, it seems to be at least intermediate level, if not advanced.


I agree with you about this. It does the job once you understand it. It’s even quite logical, in its own way. However, I still think it should be changed to be easier to learn.

I still vividly remember my utter confusion with the module system. My early Rust code has extern crate out of place in submodules, use ::std everywhere, and other nonsense. I was incredibly frustrated when I “couldn’t” move simple code to another file.

I wish I didn’t go through the pain of learning it. It wasn’t worth it. It’s different than modules in all other languages (no other language has mod/use split, and most don’t even have crate/mod split)

Rust has lots of features that are significantly different, but they’re different because they’re fundamentally better. I think the current module system is usable, but I don’t think it’s so much better to be worth learning.


Thank you very much for putting this table together!


Alright, as promised, I’ve written a new blog post following up on this discussion and spiking a rather different proposal. Please leave comments on that new thread!


To keep discussion manageable, I’m going to close this thread, and direct ongoing discussion to the follow up.