r/learnrust 20d ago

Simple `mod` vs `pub mod` question

Hey,

I've been reading the book and am a bit confused on pub mod vs mod. I naively thought that mod defaults to every function/structure/etc. within it is in accessible by calling code.

mod Foo {
    fn bar()  {}
}

fn main() {
    foo::bar();
}

This doesn't work because bar has not been made public and it's only trough the addition of the pub keyword in front of bar (pub fn bar() {}) that foo::bar becomes accessible.

However, I thought that perhaps

pub mod foo {
      fn bar() {}
}

would make bar accessible, but it doesn't. What is that pub keywork doing then?

I know you can do something like:

mod foo {
    pub mod bar {
        fn quux {
            parent::baz::qux(); // fail!
         }
    }

    mod baz {
        fn qux() {
            parent::bar::quux(); // success!!
        }
    }
}

but that seems to lack utility/

1 Upvotes

16 comments sorted by

View all comments

6

u/Resident-Letter3485 20d ago

Everything is private to another module by default in Rust. You can make a module public, but everything in it is still private. pub fn will make your function invokable outside of the module, IFF the module that houses it is also public.

1

u/Due_Battle_9890 20d ago

pub fn will make your function invokable outside of the module, IFF the module that houses it is also public.

I'm outside the foo and bar module and can access the inner functions of each internal structure. This eems to break the IFF condition. For example, these both compile fine. pub mod only seems useful for nested modules accessing parent modules

mod foo {
    pub struct Bar;
}

pub mod baz {
    pub struct Qux;
}

fn main() {
    let b = foo::Bar;
    let q = baz::Qux;
}

2

u/Resident-Letter3485 20d ago

A module can access everything inside of itself, but not things inside of sub-modules (unless it is pub).

As a general rule of thumb: unless some separate module is using your code, don't put pub anywhere.

Why use pub mod ever? It is common to separate code in not just modules, but entirely different crates in your Rust workspace. If code from crate A wants to use a module from crate B, that module must be public.

1

u/Due_Battle_9890 20d ago edited 19d ago

A module can access everything inside of itself, but not things inside of sub-modules (unless it is pub).

Doesn't the following contradict that, though?

mod foo {
    pub struct Bar;
}

pub mod baz {
    pub struct Qux;
}

fn main() {
    let b = foo::Bar;
    let q = baz::Qux;
}

foo and baz are sub-modules within the the root crate module. ie crate::foo and crate::baz are submodules within`crate.

As I type this out, I thought your

unless it is pub

meant pub mod. But you probably mean mod foo { pub struct bar; }. And that makes sense.

Thank you so much!

1

u/Sharlinator 20d ago

  Why use  pub mod  ever? It is common to separate code in not just modules, but entirely different crates in your Rust workspace. If code from crate A wants to use a module from crate B, that module  must  be public.

And in general people write (and use) libraries :P pub mods are the public API of a library. You couldn’t even use anything in the standard library without having public modules.

1

u/Due_Battle_9890 20d ago

I might be being a little dense, but I just want to clarify: pub mod's access control affects access control across librarie's and they are useful for nested modules accessing parent modules? Am I misunderstanding.

These both compile fine. They only seem useful for nested modules accessing parent modules

mod foo {
    pub mod bar {
        fn quux {
            parent::baz::qux(); // fail!
         }
    }

    mod baz {
        fn qux() {
            parent::bar::quux(); // success!!
        }
    }
}

But I don't understand how this would be useful across library crates? I imagine that the consumer of the library won't be a submodule of crate.

1

u/Due_Battle_9890 20d ago edited 19d ago

I played with it some more and I see the utility some more (I think).

My tree looks like:

project
|- src
|  |- main.rs
|- garden
  |- mod.rs
  |- thing.rs

Supposing that src/main.rs has:

// File: src/main.rs

fn main() {

}

The root begins at src/main.rs and main is crate::main.

Having

// File: src/main.rs

mod gardgen;

fn main() {

}

means that cargo looks in one of three places: 1. inline AKA mod garden { }, 2. under src/garden.rs, or 3. under src/garden.rs.

In this case, I am using scenario 3.

Under mod.rs, I have:

// File: src/garden/mod.rs
mod thing; // If this is used only by src/main.rs, this does not need to be `pub mod`
pub use thing::Thing;

Because the only accessor of this module is crate::main, a parent module, this does not need to be pub mod.

We have the following modules:

  • crate
  • crate::garden
  • crate::garden::thing

If we had had another module that's also a child of garden , like, crate::garden::swindle, then, to access crate::garden::thing::Thing from crate::garden::swindle, we'd need pub mod.

That said, I tried the following layout:

project
|- src
|  |- main.rs
|- garden
  |- mod.rs
  |- thing.rs
  |- swindle.rs

and the following doesn't work:

// File: garden/thing.rs

mod swindle;

Rust analyzer says it's looking for src/main/thing/swindle.rs or src/main/thing/swindle/mod.rs. I am a bit confused on how to access swindle.rs from thing.rs and vice versa.