Module system changes are going into FCP!


#21

The binary driver is not the same crate.


#22

How can it have the same crate name then? Do you have any example?

Sounds rather “interesting” to have two separate crates with the same, one using the other and the whole thing being idiomatic… How would you publish such a thing on crates.io?


#23

Wouldn’t two versions of the same crate have the same name and thus can’t refer to themselves by name?

e.g. if you depend on foo 0.2 and bar 0.1. And bar 0.1 dependes on foo 0.1. How will foo 0.1 refer to itself?


#24

That’s an interesting aspect. But isn’t the resolve order always (not) an issue when referring to other crates? I would assume <crate name>:: to work like just like crate:: and not point so a dependency crate, even with the same name.


#25

I think rpjohnst might have been referring to examples like this. I just created a binary project named “temp”.

src/main.rs

extern crate temp;

use temp::foo;

fn main() {
    foo();
}

src/lib.rs

pub fn foo() {
}

So it’s sort of a binary crate and a library crate both in one. And they have the same name. I’ve yet to use this pattern, but I think it’s mentioned in The Book somewhere.


#26

That’s exactly where I would deem the <crate name>:: useful because this makes the src/main.rs easy relocable to a different crate, e.g. because it grew from a small sample frontend for a library into a fully fledged application.


#27

But in this case <crate name>:: is referring to the library crate defined in the same package as this binary crate, not to the crate currently under compilation, e.g. in a project named temp

// src/lib.rs
pub const PKG_NAME: &str = env!("CARGO_PKG_NAME");
// src/main.rs
pub const PKG_NAME: &str = env!("CARGO_PKG_NAME");

fn main() {
    println!("library pkg name: {}", temp::PKG_NAME);
    println!("binary pkg name: {}", crate::PKG_NAME);
}

Notice that both the rustc invocations have the same --crate-name specified:

> cargo run --verbose
   Compiling temp v0.1.0 (file:///tmp/tmp.zdek3m7pjv/temp)
     Running `rustc --edition=2018 --crate-name temp src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=22275adfde737185 -C extra-filename=-22275adfde737185 --out-dir /tmp/tmp.zdek3m7pjv/temp/target/debug/deps -C incremental=/tmp/tmp.zdek3m7pjv/temp/target/debug/incremental -L dependency=/tmp/tmp.zdek3m7pjv/temp/target/debug/deps`
     Running `rustc --edition=2018 --crate-name temp src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=4babd7bb15cfb736 -C extra-filename=-4babd7bb15cfb736 --out-dir /tmp/tmp.zdek3m7pjv/temp/target/debug/deps -C incremental=/tmp/tmp.zdek3m7pjv/temp/target/debug/incremental -L dependency=/tmp/tmp.zdek3m7pjv/temp/target/debug/deps --extern temp=/tmp/tmp.zdek3m7pjv/temp/target/debug/deps/libtemp-22275adfde737185.rlib`
    Finished dev [unoptimized + debuginfo] target(s) in 0.43s
     Running `target/debug/temp`
library pkg name: temp
binary pkg name: temp

If the current crate’s name was added to the prelude as an alias of crate then how would the binary be able to refer to the library?


#28

Thanks for the example, that clears it up!

Here’s the thing: I was not aware that binaries next to a library automatically up in their own crate. Essentially the behaviour I wanted to see is already there.


#29

I like uniform paths but I don’t like relative use statements. I would prefer to have uniform paths (they are actually more straightforward than anchored paths where there are confusing differences in use statements vs elsewhere) but only allow absolute paths in use statements. Relative imports are the thing most people don’t like in uniform paths, but it is in no way an essential part of the proposal.


#30

Anchoring definitely.
These should really be explicit and absolute, it is a easier mental model and normally what I try (and see people trying) first as it is the natural way when mentally mirroring filesystem layout with module layout.


#31

Essentially the only thing uniform paths has that anchored paths does not is relative use statements. Or in other words, anchored paths is “uniform paths but only allow absolute paths in use statements.”


#32

I’m pretty sure that’s not true…? You can still use super:: and self:: in the anchored proposal (unless I’m seriously misunderstanding something) which are relative paths.

As far as I can tell, the only difference between the two proposals is that anchored paths require self:: to access local items from use statements, whereas uniform doesn’t. The two proposals are almost identical.


#33

They’re relative but not in the sense I meant, which was relative paths as you can write them in expressions, without self:: or super:: (as you describe in your next paragraph). We’re saying the same thing.


#34

Ah, gotcha. Sorry for the misunderstanding. :slight_smile:


#35

That annoyance is easily tempered with the statement use x::y::z as z, isn’t it?


#36

While I think I’d prefer uniform paths, because they behave more consistently, I think both designs are a step into the right direction.

This really seems to be an improvement large enough for me to consider moving my Rust version baseline from Rust 1.13 up to some more recent version including this change!


I would really prefer it though that even if one variant was chosen for Rust 2018, the other variant was retained for at least a few more minor versions, to give people outside language development venues to make up their minds.


#37

I don’t like anchored variant, since self keyword is also ambiguous:

impl Foo {
    fn bar(self) -> Baz {
        self::qux() // is it static?
    }
}

And I think that it’s very “dumb”:

fn main() {
    mod foo { 
        fn bar() { 
        }
    };
    foo::bar(); // ohh, this is external...
    self::foo::bar(); // what is `self`?
}

Therefore I’ve voted for “uniform” variant.


But anchored variant where self is replaced with mod seems to be a better option:

impl Foo {
    fn bar(self) -> Baz {
        mod::qux() // it surely refers to module
    }
}
fn main() {
    mod foo { 
        fn bar() { 
        }
    };
    foo::bar(); // ohh, this is external...
    mod::foo::bar(); // this is from `module` for that external crate
}

Also, it will be more consistent alongside with crate keyword


#38

+1 for anchored paths, we use them and we didn’t have pain with it yet.


#39

As far as I can tell, the only difference between the two proposals is that anchored paths require self:: to access local items from use statements, whereas uniform doesn’t. The two proposals are almost identical.

As far as I see You’re right.
But to be obliged to explicit everything reminds me of Java, c# and so many other languages where the whole syntax is “explicit oriented”.

What’s making rust so exceptionnal for me is that it’s an even faster language than any other one (but C I think … ?) - that’s keeping a very efficient syntax (clear, yes, but that needs very short source code to make great things). At contrary with Java or any other that are using strong typing and long keywords like private, public, delegate new repeatedly in declaration; or that are requesting every very short operation to be very explicit like myobject.ToString().Add(someother.ToString())

Well to be short, what’s make Rust or Python so simple and powerfull, in their syntax, is that it’s kept light and clear. And implicit paths allowed by uniform paths work in this way.
I would definitely prefer uniform for that.


#40

@jimy-byerley

Agreed, I would prefer uniform paths. I don’t see the anchored variant as meaningfully more explicit: if non-anchored actually causes confusion, then we should also require anchored outside of use statements, where the confusion potential is (IMO) even higher.

But I also don’t actually think it’s a big deal either way. Both proposals are great, and I’ll be perfectly happy with either one.