Pre-RFC: Add FromIterator to the prelude


#1

I would like to propose adding the FromIterator trait to the prelude.

Motivation

Code like the following is very common in Rust, especially (but not only) in documentation and examples. This exact line occurs four times in the std::collections::HashMap docs and tests, and similar lines are used throughout the example code for other collections and iterators:

let map: HashMap<_, _> = vec.into_iter().collect();

When the FromIterator trait is in scope (and default type parameter fallback is enabled), this could be written:

let map = HashMap::from_iter(vec);

This is shorter and has less extraneous noise, making it easier to write and to read. It is especially good in tutorials and other documentation for beginners because it avoids things like the turbofish operator or the _ placeholder that require additional explanation. The main advantages are:

  • It looks like other constructors, with the type name preceding the function name, and thus requires no type annotations.
  • collect can be called only on an Iterator, while from_iter takes any IntoIterator. This means explicit .into_iter() or .iter() calls can be eliminated in some cases.

(Note that collect may still be more readable when it appears at the end of a chain of other iterator methods and/or its return type is inferred.)

Of course you can import FromIterator explicitly, but in small examples and tutorials, this cancels out any length benefit. In larger programs, adding an import is not a problem but I believe collect is still generally used instead of from_iter—not because it is always better, but because it’s lower-friction (due to the prelude) and better-known (due to the bias against from_iter in docs and tutorials). The FromIterator docs even state:

FromIterator’s from_iter() is rarely called explicitly, and is instead used through Iterator’s collect() method.

Drawbacks

  • Expands the prelude without adding any functionality, only an alternate way to do something you can already do.
  • Related: if both collect and from_iter become commonly used, it’s one more thing to learn (compared to a world where from_iter is almost never used).

Propose additions to std::prelude
#2

This… sounds like a great idea to me!

Due to a change in the prelude this would require an RFC, but I’m :thumbsup:


#3

This is a significant cost. The Python Zen said: “There should be one-- and preferably only one --obvious way to do it.” Keeping low the cognitive/memory load of Rust programmers is very good.


#4

Another trait that could have similar arguments used for it is FromStr, it’s interesting that it has a slightly weaker wording for it’s paragraph about being invoked via str's parse method compared to FromIterator's (“is often used implicitly” vs “is rarely called explicitly”).


#5

As long as only one is considered as idiomatic, we can add a clippy lint for it. Then it’ll be fine I think.


#6

“Switching” idioms and completely eliminating the old one is unrealistic (unless the old one was truly harmful). This will need to be accepted with that in mind IMO.

I would love to see this improvement since code in that style is easier to read and write:

  • Prefer T::from(xyz) over xyz.into() with type hint.
  • Prefer Vec::from_iter(<stuff>) over <stuff>.collect() with type hint.

#7

Of course the dream (IMO) would be to use Vec::from(hash_map) by having a blanket impl, but that will require overlapping impls.

I’ve also thought it would be clearer to have a ToString impl for all iterators of chars and strings.