Revisiting Rust's modules

I think myself that the biggest issue with Rust’s module system is language not helpful enough if you get it wrong unlike other parts of a language, which is very likely if you are learning Rust.

When making a new project in Rust, a following tree is created.

|-- Cargo.tml
`-- src
    `-- lib.rs

src is encouraging in saying to an user - hey, put more stuff here - this is a good design here as it makes it clear that you can put more files - too bad that rest of the compiler doesn’t work together with it. So they can say decide to make a file called another_file.rs, and even put some content here.

fn method() -> i32 {
    42
}

Everything compiles successfully, no warnings, now how to use that from lib.rs?

pub fn external_number() {
    another_file::method();
}

Now to compile this.

error[E0433]: failed to resolve. Use of undeclared type or module `another_file`
 --> src/lib.rs:2:5
  |
2 |     another_file::method();
  |     ^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `another_file`

error: aborting due to previous error

error: Could not compile `example-crate`.

To learn more, run the command again with --verbose.

--verbose info is useless for this issue by the way. No hints about what needs to be done. Uh, mentioning crate name will fix it? Surely, right?

pub fn external_number() {
    example_crate::another_file::method();
}
error[E0433]: failed to resolve. Use of undeclared type or module `example_crate`
 --> src/lib.rs:2:5
  |
2 |     example_crate::another_file::method();
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `example_crate`

So perhaps it should be used, I mean, that’s how it works in Perl and other programming languages. You need to import something before using it. There is use keyword, it’s surely for that, I mean, it’s very similar to something like use std::collections::HashMap so it has to be it. Also documentation for E0433 suggests using use keyword.

use another_file;

pub fn external_number() {
    another_file::method();
}
error[E0432]: unresolved import `another_file`
 --> src/lib.rs:1:5
  |
1 | use another_file;
  |     ^^^^^^^^^^^^ no `another_file` in the root

Perhaps name of crate needs to be mentioned?

use example_crate::another_file;

pub fn external_number() {
    another_file::method();
}
error[E0432]: unresolved import `example_crate::another_file`
 --> src/lib.rs:1:5
  |
1 | use example_crate::another_file;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Maybe a missing `extern crate example_crate;`?

Alright compiler, let’s put extern crate if that’s the issue.

extern crate example_crate;

use example_crate::another_file;

pub fn external_number() {
    another_file::method();
}
error[E0463]: can't find crate for `example_crate`
 --> src/lib.rs:1:1
  |
1 | extern crate example_crate;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate

But that crate is like… right here, what’s wrong with you compiler.

Okay, I’m done here, four unsucessful attempts to do something, and one misleading hint from a compiler. Like this surely can be done better, right?


My suggestion is simply to change error message so that when trying to do any of those unsuccessful attempts when there is a directory or a file with requested module name, it should instead hint to use mod keyword. Something like this possibly.

error[E0433]: failed to resolve. Use of undeclared type or module `another_file`
 --> src/lib.rs:2:5
  |
2 |     another_file::method();
  |     ^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `another_file`
  = help: modules need to be declared first
  = note: use `mod another_file` to do so

(the error message obviously should be better, I’m not good at English myself)

25 Likes