Should the Future trait be part of the prelude

To help with discovery and user-experience, should the Future trait be part of the prelude?

Personally, I think it should, but I'm curious what others feel.

  • Future should be in prelude
  • Future should not be in prelude

0 voters

It's an important trait, but not necessarily more so than all others that aren't in the prelude either.


Could you mention which? The ones that comes to mind are Read and Write. and it feels like Write is not part of the prelude since there are two Write traits (enabling write!'s "duck typing").

On the one hand, I feel like having Future be part of the prelude currently brings "just" the .poll() method call syntax* (and is thus hardly worth the trouble of adding it to the prelude).

On the other hand, since async fn is sugar for an -> impl Future function, I feel like Future is now a core part of the language, and does thus feel prelude-worthy...

* Having .poll() refer to Future::poll when lacking an inherent impl may disincentivize people from naming other (non-Future-related) methods .poll(). I guess that's good?

Users are expected to use executors, rather than poll() directly, right? So if users use async syntax, this would be only for authors writing "glue" code for futures combinators and executors. Seems niche.

I find myself importing Path and HashMap much much more often, and they aren't in the prelude.


The traits in the ops module are even more so a "core part of the language", most of them being actual lang items, but only Drop and the Fn* traits are in the prelude.

Debug and Display are also important, but not in the prelude.


I recently converted some code over to async/.await and futures-preview 0.3. In my (limited) experience, I needed to call methods on traits like TryFutureExt and TryStreamExt and did not need to call poll() directly anywhere.

I did use Future in a few bounds, but this is included in use futures::prelude::*; which I already needed for the traits above. Since these other traits aren't in std, they can't be included in the standard prelude. Therefore, I don't see a lot of benefit in including Future in the prelude at this time.


I agree that there's other things that are more suited for the prelude (like Path and HashMap) but since I think they belong in the prelude too I voted yes. I don't think external crates should be defining things named Future and I'd like to have a larger prelude in general.

:+1: -- HashMap<K, V> should definitely be there.


It doesn't help that the full path to HashMap is std::collections::HashMap, which is quite long and feels like you're accessing something niche.

Note that types are much easier to add to the prelude than traits, because traits cause method resolution ambiguity but types can be shadowed. So "HashMap should be in the prelude" has very different dynamics from "Future should be in the prelude".

Some related discussion:


Apologies if this is OT, but std::str must be a good candidate for inclusion in the prelude: it's frustrating when you do str::from_utf8 and get an error, despite just using str in some earlier code, and since str is a builtin primitive I would think it unlikely people would want to shadow it (although of course they are still welcome to).

1 Like

Another possibility is to re-export commonly used types & traits at the base std level, so you could do use std::Future, or let mut x = std::HashMap::new(), but again I'm not sure how you would choose what went in it.

Good point about str -- I often wish that the numeric modules would just work too, e.g. u32::MAX.


Seems like crater can figure out whether there is any breakage in general for adding traits to the prelude.


Yes please, how do we make this happen? (Mods: maybe this should be a different topic?)

1 Like

File a PR most likely :slight_smile:

1 Like

Having HashMap in prelude makes it harder to swap out a custom version of HashMap in your codebase. I know that your imports shadow the prelude. But it is easy to end up using the std HashMap without indenting to while adding/modifying code because the compiler wouldn't complain about missing imports.

We should be careful about adding things to the prelude which might have more than one obvious implementation.


@manuthambi Isn't that true for existing things in the prelude as well? E.g. Box, String, and friends.

Well, Box has one cannonical implementation and that other implementations don't make sense (by making Box more than just a owning pointer to some data). With String, yes there could be multiple implementations, but String are used far more than HashMap, so it makes sense String is in prelude.

1 Like