Revisiting modules, take 3

Thanks for writing up the next iteration. My reply to the last iteration. The rate of parts I agree with / parts I disagree with has mostly stayed the same.

I'm still strongly against deprecating explicit mod. That's a bad idea and it means you need to open the file view (which I hate opening and which is highly inconvenient to use in larger projects) and do all kinds of hacks like defaulting publicity to pub(crate) (which makes stuff harder for people who want to do stricter crate privacy).

Second, I want to repeat that I'm a great fan of the concept of separating use from the local crate, and separating use from external third party crates. The concept of from use is really awesome! I'm open to any other syntax that has been proposed (including the @ notation and your proposal), as long as it keeps the separation.

I'm not really a fan of

use std::io;
mod bar {
    use io::{Read, Write}; // NOTE: No `std::`
}

Its definitely not nice (lets call it "bar example" below) and think it should be treated like a bug. But I do like:

use std::io;

fn foo() -> io::Result<()> {
}

Because it allows some shallow level of scoping without importing everything from io or having to provide an explicit list. You can easily ctrl-f for io:: and you find everything you need!

And I also like the "everything is an item" rule. It keeps concepts consistent. In fact, recent movement has been to add consistency here, by adding macros to the traditional namespacing system, not to remove it. So this change would be against the general trend.

Regarding the "bar example": you have taken it as example of how "everything is an item" is bad. I don't think this is actually due to that rule, but more because use is not consistent with other items. Because for other items, the same setup fails:

fn baz() {
}

mod bar {
    fn foo() {
        baz(); // error: cannot find function `baz` in this scope
    }
}

I do think we should keep the "everything is an item" rule, and address your issues in other ways instead:

  1. Deprecate extern crate and let users do from crate use or use @<crate>::<path> instead.
  2. I think this can be fixed by better teaching! Just expand documentation. The separation of use and mod is really great and allows you to have public modules and private ones.
  3. To make the "bar example" an error which it deserves to be, you should just make use look into the super module for any uses. If you instead had to write use super::io::{Read, Write}; I think this would be very obvious.

As I like the "everything is an item" rule to be kept, I don't think we need to replace pub(use) with pub extern.

I disagree that multi-crate projects abide the rule. In fact, multiple high quality projects don't abide by the rule:

  • main rust compiler
  • cargo
  • servo

And there is an actual reason why they do it: the src directory is only overhead for them. The src directory makes total sense if you have a single crate project directly in the main directory of your git repo. Here you have lots of files like README or .travis.yml or LICENSE-* that are clearly no rust source code and where a separation is a good idea. But if you have a multi crate project, those files are already separated from the source code by the crate directory layer. There remains one sole file which gets separated: the Cargo.toml file. And doing this additional layer for one file is not really useful IMO.

The module system is not a hard to understand part of the language and having patterns absolutely 100% consistent over all projects shouldn't be so important that you are okay with making coding harder for the contributors of multi crate projects. I guess you'd argue that this is in order to make it easier for new contributors to join, well I don't think that understanding that there is no src directory is really a big leap.

I'm a big fan of having a consistent build system, especially considering what an inconsistent mess C/C++ buildsystems are, but this doesn't mean that there should be no way in cargo to adjust the patterns a little bit to make them best suiting.