Difficulty using mod with paths

I’m unable to understand how mod works. I've read chapter 7 from the book, read questions posted in various discussions and I’ve read tutorials. I can get mod to do simple, basic stuff, but nothing beyond the primitive examples supplied.

Similar to an example in the book, let’s say a project is divided in 2 directories:

src
 └── front_of_restaurant
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
 └── back_of_restaurant
     ├── cooking
     │   ├── prepare_appetizers
     │   └── cook_main_dishes
     │   └── prepare_dessert
     │   └── clean_up
     └── management
         ├── order_supplies
         ├── assign_work
         └── balance_accounts

What I feel the documentation does not cover is if, from take_payment, I need to call balance_accounts, located in a very different section of the code.

So I'm a few levels down in front_of_restaurant and I want to call down into back_of_restaurant. In the calling code (in take_payment), I've tried the following:

mod back_of_restaurant;
pub mod back_of_restaurant;
mod src::back_of_restaurant;
use back_of_restaurant;
use std::back_of_restaurant;
mod ::back_of_restaurant;
mod crate::back_of_restaurant;

...and several other variations.

[Of course, I could also include the actual call itself, but the compiler never gets that far.]

All variations fail. Most result in:

       ^^^^^^^ no 'back_of_restaurant' in the root     (or worse errors)

No 'back_of_restaurant' in the root? Looks to me like it’s there. I can code mod back_of_restaurant in main.rs up at the top (i.e., src dir) level and it works great. From main, starting at the top, I can run balance_accounts with no problem (after qualifying it properly). Why can this not be done from take_payment? I’ve coded pub in all legitimate locations, so I don’t think it’s a visibility issue.

I find this quite frustrating because much of the discussion printed in the documentation deals with "absolute paths". But if absolute paths were really in effect, I should be able to move a module to any arbitrary location and it would still find balance_accounts. Currently only main (top level) or "cousin" modules within back_of_restaurant succeed with the mod statement.

Can anyone enlighten me? If this is clearly explained somewhere, feel free to berate me and call me names (but just remember to tell me where the explanation can be found). If it’s not explained somewhere, then how did you figure out how mod works?

The key to understanding it is that mod works exactly the same way as struct, fn, and enum. It defines a new named thing exactly where you put it.

If you defined struct Foo in the same file, it's already there, and you don't follow it by use Foo. If you defined struct Foo in some other module, you'd use crate::some_other_module::Foo. And modules-in-modules work the same.

use paths ware always absolute. The top-most module of your own library crate is referred to as crate.

4 Likes

Aren't they relative by default (in 2018 edition)?

mod foo {
    mod bar {
        pub fn hi() {}
    }
    
    use bar::hi;
}

You can force them to be absolute by either using crate like so crate::foo::bar or a prefix ::, like so use ::foo::bar

1 Like

I'm not bright enough to apply these general principles* and write syntax that compiles, so it's back to shell scripting for me, I should have known this is beyond my capabilities. But I sincerely thank you both for taking the time to help.

  • which I have no doubt are accurate

Can you post a simplified example that shows your problem. That's bound to solicit constructive help from a number of frequent posters to this forum. Once you see the needed changes, you'll undoubtedly be able to extend that yourself.

Perhaps this example could be of some help:

I've put together your example using just the take_payment and balance_accounts functions. (I think the rest follows from that, but if you're still confused, please ask more questions!)

This article is the best beginner-friendly introduction to the Rust module system I've seen: https://fasterthanli.me/blog/2019/rust-modules-vs-files/

The most important thing to understand is that you never ever ever use mod to import something. You only use it to declare where a module lives in the hierarchy. There should only be one mod statement in your program for each file.

For example, this:

mod child_module;

Is 100% identical in function to this:

mod child_module {
    // COPY AND PASTE THE ENTIRE CONTENTS OF child_module.rs HERE
}
1 Like

OK, maybe I gave up a little too easily. I will read what was provided and report back soon. I was thinking of mod as if it means "import", so now that I'm disabused of that notion, I'll try again.

Thanks for the kind assistance.

1 Like

A big help. I got it working!

I got it working, thanks for the help, I was getting quite frustrated.

I don't know if it's correct, but whenever I see the keyword 'mod', I think of the word 'scope' instead. Even if not perfect, it's a big improvement over thinking of mod as 'import'.

Thanks again.

2 Likes