Modules that inherit `super` scope


#1

Since I’m on a roll today thinking about modules, here’s something I consider an obnoxious papercut in Rust’s module system is the following:

struct Foo;
// a module used to introduce an additional path component
// to some functions that all belong together, but I don't intend
// to expose outside this module
mod internal {
    fn bar(x: Foo) {} // error[E0412]: cannot find type `Foo` in this scope
}
internal::bar(Foo); // error[E0433]: failed to resolve. Use of undeclared type or module `internal`

I think this is a sane default, since it prevents namespace pollution due to pub uses. However, I’m not a fan of having to write extraneous uses to achieve this pattern.

The weakest form of what I propose is the following (syntax is a strawman):

#[sealed] 
mod foo {
}
// desugars to
mod foo {
    use super::*;
}
use foo;

Note that this is the braces form of module declaration; #[sealed] mod foo; seems very questionable, since it desugars to adding a use statement in another file. Ostensibly you could allow #[sealed] pub mod, but that’s kind of against the narrow pattern I’m proposing. I’m pretty sure this could be done with a proc macro, so maybe I should write a toy implementation to experiment with this.


#2

On phone, so expect terseness and :dog2:

  • What does the use foo accomplish?
  • use super::*; is one line. I don’t understand how any proposal could make this more ergonomic.

#3

So I wrote this big long response to your points, stared at them again, and realized that what I’ve described isn’t really what I want. I think I really want two things:

  • For mod foo { .. } automatically dump their contents into local scope, so they can be referred to by foo::bar instead of self::foo::bar. I’ve been writing Rust for over a year now and I still forget that I need to do that.
  • To not have to write use super::* in block-style modules, and I always forget to include it, because I sort-of expect that I can just wrap a bunch of items in a file in a mod foo { .. } and for everything to still work (after I add foo:: in the necessary places). Maybe, what I secretly want is for diagnostics to suggest importing with super in situations where it’d be better than a fully-qualified path?

Like, the more I think about it the more I feel like Rust’s module system, with all its problems, already does a better job of organizing code than, say, packages in Scala.

Also it’s late, so this might all be much more coherent in my head than on paper… -_-


#4

But it doesn’t actually do that. Paths outside of use are already relative and do not require self, and there is nothing you can use to avoid writing self in the places where it is required. (which are use statements)


#5

Huh… ok. You’re right, I was totally hallucinating how paths outside of use worked last night. =S Thanks for pointing that out for me.