Module local preludes

If rustc interpreted use modpath::**; as use modpath::prelude::*; then modules like core::future or std::sync could conveniently provide their own prelude.

These optional per module preludes would simplify imports more effectively than corresponding proposals in the contentious 2021 edition prelude RFC.

As an example, use core::mem::**; would expose replace and swap, but not ManuallyDrop or discriminant. And use core::fmt::*, use core::io::*, use std::sync::**;, use std::futures::**; all bring similar benefits.

There are already crates like rand that provide some prelude module, which then benefit from the ** syntax too.

We do not require a special syntax to save typing 8 characters of course, but likely the ** helps establishes a convention of providing preludes, or even local prelude in large projects, which then helps focus user attention upon core functionality and expected utilization.

We could experiment by adding unstable modules like core::mem::prelude that simplify imports, but initially without the special ** syntax. We could then add the ** syntax once these convince everyone that local preludes better communicate expected usage and common functionality.

2 Likes

I'm not convinced that module is the right granularity for a prelude.

See how futures::prelude imports things from 4 different modules, for example.

Or if I imagine the CLI prelude I brought up in the RFC thread, I'd expect it to include things from at least the path and fs modules, but probably more as well -- maybe ffi for OsStr, for example.

6 Likes

I do think WGs establishing their domain specific prelude sounds interesting. In nightly, folks could experiment with an unstable use std::preludes::wg::*; too, or more likely a top level preludes crate.

There is nothing wrong with multiple import paths for the same item though, so module local preludes might still make sense. It's requires looking at both options in detail I think.

Among other concerns, I don't like ** for this, it's very minimally different from *, to the point where I'm not sure it'd stand out if i ever cared to look at an import list and try to figure what it's doing.

3 Likes

There's already a convention of providing preludes, and I don't think we need a special syntax for importing them. I think this abbreviation adds to language complexity and surface area in a way that far outstrips any benefits it would provide.

9 Likes

Interesting, so maybe then the best approach would be a preludes crate that users accessed like use preludes::wg::*;, roughly like scott proposed?

I think it'd probably want to be a crate per working group or framework or something, and probably not in std.

Like I could imagine the CLI one pulling in crates like clap in addition to various std things.

This sortof mixes with the stdx (GitHub - brson/stdx: The missing batteries of Rust) idea, but with the more limited scope of a particular domain.

(One massive prelude crate would have too many dependencies and features to be practical to use, I think. So separate ones in the ecosystem feels better to me.)

2 Likes

I think then a remaining question is whether there should be any default behavior, like use crate; triggering the inclusion of use crate::prelude::*; or something (so like the ** idea but only the bare crate).

It would be nice if there was a way to import items into the current module as well as all its submodules, so you don't have to repeat the import in every file. This would make user-defined preludes much more convenient to use:

global use prelude_cli::*;

Edit: I just realized that this would have the same effect as stabilizing #[prelude_import].

3 Likes

I sympathize with the sentiment but it makes it very hard to search for the import point of an item if it's not in the same file.

In theory you could have

file use foo::*;

Or something like that for all submodules implemented in the same file, but that would cover almost only mod tests in practice.

Yes, this is exactly what I want! If this was stabilized, I wouldn't mind adding bunch of common preludes somewhere in std. (E.g. std::prelude::fs, std::prelude::mem, std::prelude::collections...)