Henry Gomersall
Henry Gomersall

Reputation: 8712

How can a Rust module have the same name as a const in the same namespace?

I came across some code in a piece of published code that had something like the following structure (which compiles and runs fine):

pub mod foo {
    pub const BAR: u32 = 53;

    #[allow(non_snake_case)]
    pub mod BAR {
        pub fn eep() {
            println!("This is attached to BAR");
        }
    }
}

fn main() {
    println!("Hello, world!, {}", foo::BAR);
    foo::BAR::eep();
}

This seems strange and interesting to me. The strange bit being BAR being defined as both a const and a mod.

Is this idiomatic Rust?

What is going on here? Should I be able to find out about this in the docs? When is such a pattern valid?

I can see that this might be useful, but is there some really compelling use case?

Upvotes: 3

Views: 2812

Answers (1)

Shepmaster
Shepmaster

Reputation: 431669

No, it's not idiomatic, and the compiler already tells you this:

warning: module `BAR` should have a snake case name
 --> src/main.rs:4:13
  |
4 |     pub mod BAR {
  |             ^^^ help: convert the identifier to snake case: `bar`
  |
  = note: #[warn(non_snake_case)] on by default

The warning has been silenced in the code you have presented, for whatever reason.

normally whilst programming one can't attach the same label to multiple constructs in the same namespace

That's correct. Modules and constants are in different namespaces. There are three namespaces:

  • types
  • values
  • macros
fn main() {
    macro_rules! BAR { () => {} }
    mod BAR {}
    let BAR = 1;
}

Modules are in the type namespace.

I don't understand what BAR is. Is it a module, or is it a const?

There's one of each.

See also:


I'd probably write this:

pub mod foo {
    use std::fmt;

    pub const BAR: Bar = Bar(53);

    pub struct Bar(u32);

    impl Bar {
        pub fn eep(&self) {
            println!("This is attached to Bar");
        }
    }

    impl fmt::Display for Bar {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            self.0.fmt(f)
        }
    }
}

fn main() {
    println!("Hello, world!, {}", foo::BAR);
    foo::BAR.eep();
}

Upvotes: 4

Related Questions