I love rust, but one thing about modules is aweful!

cc @steveklabnik

this seems to be a docs issue.

Why is this a problem? If you do extern crate my_crate to reference the library you're using then can either use all the names you want explicitly or via globs as noted already. The fact that you're writing main.rs at all suggests you're using some library. Usage of extern crate then makes sense.

The fact that the lib.rs and main.rs are in the same folder is somewhat irrelevant. One is a library for the other to utilize. The library should be utilized in the same fashion the rest of the world will have to.

1 Like

You can also write a path relative to the parent module with super, like super::foo::bar.

I also had a hard time understanding at first what that mod in lib.rs does, it's not just schmitch :wink:

I somehow expected that a use in lib.rs would be enough to link a module in.

Too many ways to do it, too many ways that are undocumented.
Currently I think linking and importing / including code is really important and should be way more documented.
Like how to split your code in multiple files, how to split your binary, how to split your code in libraries.
These things needs to be well understood for a system level language. And in C/C++ there is enough documentation in the internet, how to do it.
But when I know look at my started thread, I see lot's of people suggesting me a simple problem.

And now my issue is even bigger, now I ask me should I even prefix it with the module or should I just include the functions. There is no "best pratice" yet.

I would say this isn't something that needs a "best practice". It is a matter of individual readability and personal preference, similar to deciding between import x; x.y and from x import y; y in Python.

In general, Rust is pretty good at putting things where "best practice" rules make sense into the language itself or lints (e.g. name conventions, unused API elements). Many of the additional lints provided by clippy are already pretty opinionated.

I may be missing the question but when I'm writing applications I usually end up with a structure like:

main.rs
mod_a\mod.rs
mod_a\struct_aa.rs
mod_a\struct_ab.rs
mod_b\mod.rs
mod_b\struct_ba.rs
mod_b\struct_bb.rs

And yes main.rs has the:

mod mod_a;
mod mod_b;

And mod_a\mod.rs has:

mod struct_aa.rs
mod struct_ab.rs

But it's only main.rs and the various mod.rs files that have the "mod" commands. My main.rs also ends up being very small because pub fn main() usually creates a few objects and then jumps into one of those objects to perform the actual work. So the number of "use" commands in main.rs ends up being quite small.

Then where the real work is going on like in struct_aa.rs I have the various includes:

use mod_a::struct_aa::ObjectAaa;
use mod_b::struct_bb::{ObjectBba, ObjecBbb};

For the objects that source file needs to use/reference. But no "mod" commands there.

I still don't see what the problem is. You saw the crate docs but stating the examples are almost all about external crates is not true at all. The entire first half of the page is dedicated to examples without extern. It includes examples where modules are inlined and then split up between files showing how to do each.

Then your examples seem to ask questions which completely ignore that page's recommendations by doing something completely different.

This is fine but what the problem actually is isn't very clear. The only thing that is clear is that the docs are apparently confusing. @gkoz gave a good example of how to inline a module but it apparently wasn't helpful because it's not what the OP was trying to do.

If all you are trying to do is use the library you locally created, look here. If you could clarify what the issue is, that would be helpful.

1 Like

It's true that the crucial to understand relative/absolute paths distinction and the ::foo::bar::baz() syntax are tucked away in the very bottom seemingly a part of the "Re-exporting with pub use" section making them easy to miss.

Also it's not obvious that mod foo also imports the module for you.

Documentation tends to be really good (TRPL, Rustonomicon and if can buy, Rust Essentials) ... but I think the modules (code organizing ! :D) area of the docs could use a little love, I also had a bad time with it :c

1 Like

Which part? What is confusing about them? Vague criticism isn't very helpful. If you want to criticize, be specific.

This is the only concrete statement I see in the whole thread about what the document lacks and the first part is incorrect, the second part might be correct and I'm not sure about the third.

Either way, there hasn't been a question here about explaining those latter 2 details or discussion about if they should be added to the docs.

Oh. I didn't know that we don't need a super:: prefix in use mymodule; here. How does it work? I thought name lookup was limited to the local module. Apparently, it is not. Is this documented somewhere?

It is documented.

Well, by default, use declarations are absolute paths, starting from your crate root. self makes that path relative to your current place in the hierarchy instead. There’s one more special form of use: you can use super:: to reach one level up the tree from your current location.

This should probably live in the "Importing modules with use" section.

1 Like

No need to be aggressive, I doubted about posting because of the tone of the original poster ... In my particular case I had issues understanding how "extern crate" works in modules, how things like the ones I cite below are supposed to be arranged with modules (and in particular, inside a project with a lib and a bins):

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
#![plugin(regex_macros)]

I kinda revolved TRPL, Rust Essentials and a few Stack Overflow questions and I could get going. I wanted to split up code of a backend project at work (to run "in production" -ehem- as I had freedom to choose the language for a week trial of that app and everything was quite ok :smile: .. the code was decent, but I didn't like having a massive main.rs file or doing external crates for every module as I was kinda doing with Rust ) for a magazine deliveries and tracking app. This was after kinda 5 months toying with rust for things similar to these I use at work (so I wanted to push it to a production project we're I could give it a shot trying and use it as a small case to see if it could be considered for other projects)

So far, so good ...on the second project I wrote (same, for work and for production use as an alternative to writing it in Python) I could dive a little deeper at the details of organizing the code (re-exporting, more complex modules) after some exploring and googling I think i kinda got the things with the modules going and ok, but it wasn't everything as clear (mostly the plugin, feature, paths and re-exporting and take that to a lib and bins project) and took more time to grasp than the rest of what I read.

Sorry for my bad english, and for massive post :expressionless:

Actually, I was trying to draw out the problem. As I see this thread, there are over 30 responses and the original question isn't answered. I would rather draw out specific questions than watch people answer what is apparently the wrong question.

Okay, so can you give a specific example where extern crate other_crate isn't nice to use?


Regarding #![...], that's a good question which the docs don't discuss. So, if the basic module has the following form (taken from defining modules):

lib.rs:

mod english {
    mod greetings {}
    mod farewells {}
}

mod japanese {
    mod greetings {}
    mod farewells {}
}

When subdivided this becomes the following where the nested files will also have their own files in a similar fashion:

lib.rs:

mod english;
mod japanese;

These are completely equivalent and therefore placing an inverted attribute (#![...]) in the 2 line lib.rs file is equivalent to placing it in the 8 line lib.rs file. Because #! attributes apply to the enclosing item, they must be applied at the top. main.rs being a module itself, uses them in the same fashion.

For example, this will configure your main.rs module to only compile under cargo build and not under cargo test. It applies to all that is contained inside the module inside main.rs:

#![cfg(not(test))]
mod inner1 {
    mod inner2 {}
}

fn main() {
    println!("test");
}

The set of feature attributes have slightly different rules. They still apply to the enclosing item but are only valid when the enclosing item is a crate. As such, #![feature(step_by)] and #![plugin(regex_macros)] are only valiid at the top of lib.rs and main.rs and other such modules. So, while this would be valid:

#![feature(step_by)]
pub mod inner {
    // Valid. `cfg` isn't a compiler feature.
    #![cfg(not(test))]
    pub fn threes() {
        for i in (0..10).step_by(3) { println!("{}", i); }
    }
}

fn main() {
    inner::threes();
}

This is not.

pub mod inner {
    // Not valid. `feature` is only applicable to crates.
    #![feature(step_by)]
    pub fn threes() {
        for i in (0..10).step_by(3) { println!("{}", i); }
    }
}

fn main() {
    inner::threes();
}

I'm gonna file an issue for this. Let me know if this was understandable because it may be useful when trying to improve the attribute docs. Also, please respond with an extern crate example that you find awkward and annoying if you can think of one. Maybe it's just a bug or a misunderstanding or something else.

[EDIT]

Issue filed

1 Like

I'll throw my $0.02 in here since I recently hit the same teething issue.

I started with a simple desire: "gee, this is a fair amount of code, I'd like to shove all of this stuff into another file so it doesn't clutter up main.rs quite so much!" Having cut my teeth (and my gums, and my fingers) on C/C++, I pushed the code into another file, call it args.rs and thought "Oh my, how do I include a file?"

There were some docs on modules in the Crates.io docs, I think it was. But I wasn't sure that was what I wanted, because I had to put this strange mod args; call in main.rs as well as the more understandable use args; or whatever it was.

Speaking of which, what does mod foo; actually do? I'm still not totally sure.

I think the docs could be improved (at least IMHO) if they presented a few simple use cases, and might I campaign for mine, which is just the simplest of "how do I push some code into another file and then use it from some other files?" It doesn't have to be hard, I think, but just a simple "this is the pattern, we have this mod statement in the original file for reasons that mysteriouspants still doesn't know about, and we have this use statement so you can use the members of the secondary file marked with pub." Just getting that far, I think, would alleviate some of the initial confusion.

These being my $0.02, I should disclaim that they are worth exactly that much (which isn't a lot).

This is explained here within the first 10 lines. What about that section is confusing? Clearly it is confusing because multiple people have stated it is.

I could try to elaborate but I don't see how it needs any help.

I think I finally understand crates and modules mostly fine now, but for a long time I found them confusing (even after reading the page in TRPL). Like @mysteriouspants, I didn't really know what mod foo; did.

I think I read a comment on Reddit that helped me a lot. I wish I could find it now. It said something about modules making more sense when you think of the unit of compilation as the crate (the lib.rs or main.rs). By default, that file is all that is in the create. Then you list in that file which files to add to the crate (with mod). Reading TRPL, those facts didn't sink in very well (like the how special lib.rs/main.rs is). I think the high-level could be more clearly explained. I think TRPL explains the rest well.

I'll look more for that comment.

Yeah, a guide like that is exactly what I was thinking there should be! I haven't the foggiest how it escaped me the first five times I went looking for it. I eventually went and looked at other crates in the wild (from my duck blind with my binoculars) to see how they did things. I remember finding it very foreign that all the mod statements were stuffed into one file. It seemed to me that the mod declaration should go in the file the mod contains (I did, at one point in my life, program Java, so think package statements)!

But what do I know? Well, now I can see that mod serves (apparently, I could still be wrong) to tell the compiler where to look.

I'm not saying the system as constituted is bad! I just am saying that apparently it's different enough from what I knew before that a little more hand-holding might be in order.

@jminer So, I don't see a lot that is actionable here. I wonder if the fact that it's fairly different from C++ (I think it is) makes it confusing for some people...

@mysteriouspants Yeah, you're on the right track. The issue you ran into then isn't that the docs are bad, it's that the module docs are hard to find. Search would probably help. Maybe having more sidebar sections would be a good idea. I'm hesitant to do it though because I did the rustbyexample sidebar and don't want to try to reformat the book structure into a rustbyexample clone.