|
I'm glad that Rust has no `auto`. I find this: fn map<U, T, F, I>(it: I) -> impl Iterator<Item=U>
where I: Iterator<Item=T>, U: From<T>
{
it.map(|t| From::from(t))
}
infinitely more readable than fn map<U, T, F, I>(it: I) -> auto
where I: Iterator<Item=T>, U: From<T>
{
it.map(|t| From::from(t))
}
The type signature of the first one clearly tells me that the return type is an `Iterator<U>`, even though the actual type cannot be named because of the anonymous closure.The second one leaves me guessing what the return type is. If the actual type cannot be named, it is rarely the case that this is all there is to it. Usually, users are expected to use that type "somehow" (it is a `Range`?), and that means that there are some interfaces that these types implement. |
For example, the return of map could provide indexing, or it could provide forward and backward iteration, or it might have methods that are completely unrelated to the type.
There is no good reasonable and non-confusing way to describe all the things map could return depending on the input. It's much better to just describe it conceptually in the human-readable docs, and let the person understand the result.
I'll note that just above the function map in D's source is the documentation. You just need a little more context, and it will describe what map returns in a much more (IMO) useful fashion than a return type that might be several lines long and consist of various static conditionals:
"The call map!(fun)(range) returns a range of which elements are obtained by applying fun(a) left to right for all elements a in range."
This is the difference between duck typing and generics.