Skip to content

Option::map_iter() to create an iterator from Option #626

@ChayimFriedman2

Description

@ChayimFriedman2

Proposal

Problem statement

It's common to have an Option containing an iterator, or something that can be transformed into an iterator, and wanting to get an iterator out of it. This can be done with option.into_iter().flat_map(|it| it.iter()). The verbosity is okay (although not great, and this isn't easily discoverable), but this is not as efficient as it can be, because FlatMap/Flatten need to handle iteration for generic iterators, which can be a lot slower. Internal iteration is often fine (the FlatMap can be optimized) but external iteration uses way more instructions than needed. As an example, see this godbolt link, which contains way more instructions than needed.

Code for the godbolt link:

unsafe extern "C" {
    safe fn black_box(v: &i32);
}

#[unsafe(no_mangle)]
pub fn foo(v: Option<&[i32]>) {
    for i in v.into_iter().flatten() {
        black_box(i)
    }
}

In addition, FlatMap/Flatten can't provide an accurate size_hint()/TrustedLen, which can make collecting even slower.

Motivating examples or use cases

The rust-analyzer codebase contain dozens (more than 20) instances of the abovementioned pattern.

Solution sketch

Include a method in Option, that takes a callback that returns an iterator and returns an iterator for that behaves like FlatMap but is specialized for Option.

I chose to call this method map_iter(), but I'm not really pleased with this name, I just don't have a better one. So I'll be happy to hear other opinions.

Alternatives

At least the size_hint() part is fixable I believe with specialization. The next() part is harder, it may not be possible to specialize it to the most efficient codegen.

There's also the argument that adding a method purely for the sake of optimization isn't a good idea. While I do think a special method is also more easily discoverable and nicer to type, the main motivation is indeed perf. But I do think if we can't get this level of perf from alternatives it's worth adding the method, even for perf sake only.

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions