Define a preference for mod.rs over foo.rs

If one has a foo/mod.rs and a foo.rs, mod foo; should prefer the foo/mod.rs.

Use-case: Testing! Sometimes you need a complex "dummy downstream crate" for testing with, and this would provide just that. You'd be able to have tests/common.rs for testing said dummy module, and tests/common/mod.rs for defining the actual module.

This seems like it could be confusing to people who are reading your code later, who might see mod common; and assume that it imports the common.rs. Thus, it's almost certainly better to simply choose distinct names for them. Is there anything forcing you to use the same name?

3 Likes

We would think it's less confusing that tests/common.rs should test tests/common/mod.rs as opposed to testing some other part of the crate. One can always add clarifying comments to the file, anyway - any confusion would only be temporary.

Do you mean, "as opposed to something with a different name testing tests/common/mod.rs"?

My first thought is to name the outer file tests/common_tests.rs - a little redundant, but it's obvious what it means. Where's the confusion?

The fact that there's both a tests/common.rs and a tests/common/mod.rs is already confusing in itself.

6 Likes

Better than having tests/common.rs and tests/common/submod.rs at least.

tests/common/submod.rs would be bad, yes. But Rust isn't forcing you to do that. You can do what I suggested: make tests/common_tests.rs, which can say mod common; to import tests/common/mod.rs. (That way, neither file is named tests/common.rs). This is a better naming convention, because the tests and the submodule are different things, so they should have different names.

If there's a situation where Rust is forcing bad naming conventions in some way, what we should do is to come up with a feature that would allow good naming conventions instead. The proposal in this thread would allow different naming conventions, but they are not good – only bad in a different way.

Wouldn't any kind of preference to mod.rs run contrary to Rust 2018 path clarity?

1 Like

Why does this depend on editions for seemingly no good reason other than forcing ppl to use 2018 edition? (which lacks extern crate crate declarations)

Anyway why would it go against that? It's currently an error and it'd only be useful for binaries and tests.

... Actually, thinking about it, it'd be really useful for binaries and less so for tests. But anyway.

Well there will soon be a 2021 edition and the path clarity from 2018 still applies for 2021. (I am not a member of any team).

Personally, I think that not having this be a collision (thus a failure to compile) would be bad (if it isn't so already).

We think being able to have src/bin/foo.rs and src/bin/foo/mod.rs would be great. (and better than making bin a keyword/banning "bin" modules for the sake of having src/bin/foo/bin.rs) And it would also work for tests.

My interpretation of the intent of the "Rust 2018 path clarity" proposal is to eventually phase out mod.rs, and "define a preference for mod.rs" runs directly contrary to that.

I wasn't sure why, so I checked, and in fact, using foo.rs instead of foo/mod.rs is NOT edition-gated, despite what the Edition Guide implies. That is, in Rust 1.31.0 and later, you can do it even if your Cargo.toml says edition = "2015".

I'm also not sure what you mean by saying that the 2018 edition "lacks" extern crate declarations. You can use them if you want, they're just optional.

3 Likes

Yeah the problem is it doesn't require them. We want/like required extern crate.

Why is that a problem?

Previously you could have a different set of dependencies for your binaries and your libraries by using extern crate. Sure, cargo didn't care about it, so you still pushed your binaries' deps downstream, but eh.

Also like literally every non-JVM language requires you to import stuff before you can use it. But regardless, this is something for a different thread.

If you don't actually refer to a dependency, it will not be linked against, nor will it's metadata even be loaded. For example

//- Cargo.toml
[dependencies]
very_big_dep = "0.1"

//- main.rs
fn main() {}

Will not link against very_big_dep, however the following will:

//- Cargo.toml
[dependencies]
very_big_dep = "0.1"

//- main.rs
use very_big_dep; // <-- referring to the dependency here
fn main() {}