Skip to content

Suggest to replace impl Iterator return types with wrapper types #5989

Open
@Luro02

Description

@Luro02

What it does

It suggests replacing impl Iterator with a wrapper type, if the function is public (other crates can call it).

The impl Trait syntax erases types completely, which makes it impossible to use them as struct fields. This can make the API of a crate less convenient, because you have to for example collect the returned Iterator into a Vec (function_returns_impl_iterator().collect::<Vec<_>>()).

The syntax should be mainly used for situations, where you cannot represent the returned value as a concrete type.

For example

use std::future::Future;

async fn hello() -> impl Future<Output = &'static str> { "hello" }

this function can only return impl Future, because there is no type for the returned value.

What is the advantage of the recommended code over the original code

The returned value can be used by other structs as fields or it could be used with functions that have bounds like this:

fn takes_iterator<I: Iterator<Item=usize>>(iterator: I);

Example

original code:

#![warn(clippy::pedantic, clippy::nursery)]

use std::iter::Iterator;

fn greetings() -> impl Iterator<Item = (usize, &'static str)> {
    vec!["hello", "hallo", "salut", "hola", "ciao"]
        .into_iter()
        .enumerate()
}

fn main() {
    for (number, greeting) in greetings() {
        println!("{}\t=> {:?}", number, greeting);
    }
}

better code

#![warn(clippy::pedantic, clippy::nursery)]

use std::iter::Iterator;

pub struct IntoIter(pub(crate) std::iter::Enumerate<std::vec::IntoIter<&'static str>>);

impl Iterator for IntoIter {
    type Item = (usize, &'static str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

fn greetings() -> IntoIter {
    IntoIter(
        vec!["hello", "hallo", "salut", "hola", "ciao"]
            .into_iter()
            .enumerate(),
    )
}

fn main() {
    for (number, greeting) in greetings() {
        println!("{}\t=> {:?}", number, greeting);
    }
}

Drawbacks

Writing wrapper types can result in quite a lot of boilerplate code that might not be worth the time, because almost every
downstream crate would just iterate over the returned value. Therefore, I suggest making this lint pedantic.

This lint can not be applied to every usage of impl Trait, so I would suggest limiting it to Iterator (can be extended in the future).

Categories (optional)

  • clippy::style
  • clippy::pedantic

Metadata

Metadata

Assignees

Labels

A-lintArea: New lintsL-restrictionLint: Belongs in the restriction lint groupT-middleType: Probably requires verifiying typesgood first issueThese issues are a good way to get started with Clippy

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions