Paths should not be "global by default"


#1

Related modules should be grouped into a single module, which means that global paths should be rarely used. Using relative paths makes refactoring (e.g. renaming or moving modules around) easier. Global paths by default also causes a lot of confusion, and the language reference does not even clearly explain the default behavior of (non-prefixed) paths.

Therefore, I think that using global paths as the default is a bad idea. Global paths should be explicitly marked as global, but I am not sure about the best way to mark them. I am also not sure whether local paths should be explicitly marked. Paths referring to use declarations should remain unlabeled, since the use declarations already make the intention explicit.

There are two ways I know that global paths could be explicitly marked.

  1. My original proposal: Prefix every global path with crate::, and deprecate the usage of the current :: prefix. This makes things explicit (probably the rust way), and makes the behavior guessable to anybody.
  2. @P1start’s suggestion: Retain the current :: prefix, but make it mandatory. This mirrors the unix file system with :: corresponding to /, self corresponding to ., and super corresponding to ..

There are three ways to deal with local paths.

  1. My original proposal: Prefix every local path with the self:: prefix. This is the most explicit way. However, there are problems when referring to types and functions in the same module.
  2. My tweak: Prefix local paths for items in submodules with the self:: prefix, while making self:: optional for types and functions in the same module.
  3. @P1start’s suggestion: Do not prefix local paths with anything (making them the default). This is the simplest way to do this, although more implicit. (The self:: prefix might also be deprecated)

Original post: I would like to propose using “crate::” for global (crate-level) paths, and deprecate paths not beginning with “super”, “self”, or “crate” unless a use declaration was used (also deprecate paths beginning with “::”). This would clear up some confusion for many people.

Also note that the reference seems to be unclear about behavior of paths that don’t begin with “super”, “self”, or “::”. http://doc.rust-lang.org/reference.html#paths


#2

Which is better for making it easier to refactor, split out modules as crates, or change module structure? I’m not completely sure, but I think relative use paths make that easier.


#3

Well… I think that using something slightly more verbose for global paths should discourage their use.

IMHO relative paths should be used whether possible, as it simplifies all kinds of refactoring, just like you said. (Also: Renaming modules is much easier with relative path, since renaming affects all global paths of all descendants, but it affects only a few relative paths.)


#4

I’m too stupid to deal with ::blah and default global. +1 for explicit self/super/crate scope.


#5

I’m still not sure about how to handle external crates, but I think there are basically 2 choices:

  1. After “extern crate foo”, the path for stuff in foo starts with “foo::” (the same thing as after “use … as foo”)
  2. After “extern crate foo”, the path for stuff in foo starts with “crate foo::” (uses a special syntax) Maybe this might be just bikeshedding.

BTW I think that (if this “crate::” syntax is to be accepted,) this probably must be done before 1.0 alpha (9th January), since this breaks a lot of code. That’s currently only 17 days left.


#6

Strong +1 on this. It was one of the biggest mistakes in Python to not separate scoping and it was only fixed in 3.x by default.


#7

I’m a little confused by this. Is this proposing that all paths must be prefixed with self:: (local), super::, or crate:: (global)?

Denying all paths that don’t start with self, super, or crate doesn’t make much sense to me, because a lot of very commonly-used things are paths, including local functions. So the following code would not work under this proposal:

fn foo() { /* do something */ }

fn main() {
    foo(); // should be self::foo()
}

I think even local variables technically are paths.[citation needed]

Also, I really like the leading :: for global paths. It mirrors the leading / in global paths to files/directories. Continuing the analogy, self is equivalent to ., and super is ...

Right now some (most?) of the confusion with paths is because of the fact that paths are normally local by default, but are global in use statements. Another solution to this would be to simply make use statements take local/relative paths by default, requiring :: for global/crate-relative paths.


#8

As for the local functions, I forgot about it. However, I think it can be solved by having an implicit use declaration in every module:

use self::{... (all functions and types here)...};

Note that this does not include submodules.


#9

Your alternative solution sounds possible too, but I think that it should also deprecate self:: paths.

Additionally, there would be no distinction between "use"ed paths and local paths.


#10

I’ve edited the post. I hope that the intention of my proposal is clear now.