Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue Iterator map_while #68537

Closed
Mark-Simulacrum opened this issue Jan 25, 2020 · 18 comments
Closed

Tracking issue Iterator map_while #68537

Mark-Simulacrum opened this issue Jan 25, 2020 · 18 comments
Labels
A-iterators Area: Iterators B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. Libs-Small Libs issues that are considered "small" or self-contained Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@Mark-Simulacrum
Copy link
Member

Added in #66577.

Open questions:

  • Implement DoubleEndedIterator, FusedIterator
  • Debug output
@Mark-Simulacrum Mark-Simulacrum added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Jan 25, 2020
@jonas-schievink jonas-schievink added A-iterators Area: Iterators B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Jan 25, 2020
@WaffleLapkin
Copy link
Member

@ollie27 noticed in #66577 (comment) that MapWhile doesn't need to be FusedIterator (and so we can remove the finished flag). However TakeWhile is already FusedIterator and we can't change that since it would be a breaking change. It may be confusing to users that MapWhile and TakeWhile works a bit differently.

How do we choose? Remove the finished flag and probably confuse some users or make less flexible implementation?

Personally I would prefer removing the finished flag, but I'm not sure.

@Boscop
Copy link

Boscop commented Feb 26, 2020

@WaffleLapkin So the reasoning that it shouldn't impl FusedIterator is that the user might want to continue consuming this iterator after it first returned None (e.g. find multiple "sections" in the original iterator), right?
Then I think removing the finished flag is the right thing to do.

Btw, since TakeWhile impls FusedIterator shouldn't we also want to add a version of it that isn't fused?

@WaffleLapkin
Copy link
Member

@Boscop Yes, one of the reasons is that user might want to continue. But it is a rare case, so it's not so important.
In my opinion, we need to remove the finished flag because there is no need for it to exist. When you need to guarantee Nones after the first None, you must call .fuse() (there is even a note in the docs that says that you should prefer .fuse() over T: FusedIterator) and in most cases, you don't need to worry because everything (for loop, fold, for_each, collect...) stops on the first None. That way MapWhile is just more zero-cost.

Not sure if we need unfused TakeWhile since

  1. we can't change TakeWhile (this would be perfect, but it's breaking change)
  2. all cases of unfused TakeWhile are covered by MapWhile. E.g. .unfused_take_while(pred) == .map_while(|it| if pred(&it) { Some(it) } else { None })

bors added a commit to rust-lang-ci/rust that referenced this issue Mar 22, 2020
…_while, r=LukasKalbertodt

Remove `finished` flag from `MapWhile`

This PR removes  `finished` flag from `MapWhile` as been proposed in rust-lang#66577 (comment).

This also resolves open questions of the tracking issue (rust-lang#68537):
- `MapWhile` can't implement both
  + `DoubleEndedIterator` (discussed in rust-lang#66577 (comment) and following comments)
  + `FusedIterator` (this pr removes `finished` flag, so `MapWhile` isn't fused anymore)
- Debug output (this pr removes `finished` flag, so there is no question in including it in debug output)

r? @Mark-Simulacrum
@camsteffen
Copy link
Contributor

Ready to stabilize?

@HeroicKatora
Copy link
Contributor

This method overall is very, very similar to scan.

// These two yield the same items.
iter.map_while(predicate)
iter.scan((), |(), item| predicate(item)).fuse()

Is there any impl (unsafe or not) that could be added to scan+fuse but not to scan and fuse alone by composition? This would be one possible way to distinguish these two methods, otherwise I see little point in adding map_while here instead of itertools.

@WaffleLapkin
Copy link
Member

Wow, I haven't thought that there is such a similar adapter...

@HeroicKatora please note that after #68820 MapWhile does not implement FusedIteraror and thus, iter.map_while(predicate) is analog to just iter.scan((), |(), item| predicate(item)).

However, I'm still in favour of adding map_while to std, because (in my opinion) there are a lot of situations where map_while is more readable than scan (()s are a bit nasty) and also scan doesn't come to mind in such situations (nobody has mentioned it for 7 months after the original PR :D).

@WaffleLapkin
Copy link
Member

Oh, by the way, @Mark-Simulacrum , as #68820 is merged, could you remove current "open questions" from the issue?

Open questions:

  • Implement DoubleEndedIterator, FusedIterator
  • Debug output

@Boscop
Copy link

Boscop commented Jun 29, 2020

I agree with @WaffleLapkin that the scan solution is very non-obvious and also harder to read for others who read the code. So I'd really prefer to use map_while.
The impl of the map_while method should maybe be written using the scan solution.

@KodrAus KodrAus added Libs-Small Libs issues that are considered "small" or self-contained Libs-Tracked Libs issues that are tracked on the team's project board. labels Jul 29, 2020
@kamulos
Copy link

kamulos commented Jul 26, 2021

Is there any status update on stabilization? This would be such a valuable function for some cases: I currently have the exact same case that is in the documentation:

.take_while(|x| x.is_some())
.map(|x| x.unwrap());

and I am not comfortable having unwrap() in the code

@WaffleLapkin
Copy link
Member

@kamulos since this method was added almost a year ago and all unresolved questions were since resolved, I believe we can start the stabilization process. Someone from the libs team needs to start an FCP.

@m-ou-se
Copy link
Member

m-ou-se commented Sep 8, 2021

@rfcbot merge

@rfcbot
Copy link

rfcbot commented Sep 8, 2021

Team member @m-ou-se has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Sep 8, 2021
@rfcbot
Copy link

rfcbot commented Sep 8, 2021

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Sep 8, 2021
@Stargateur
Copy link
Contributor

This method overall is very, very similar to scan.

// These two yield the same items.
iter.map_while(predicate)
iter.scan((), |(), item| predicate(item)).fuse()

Is there any impl (unsafe or not) that could be added to scan+fuse but not to scan and fuse alone by composition? This would be one possible way to distinguish these two methods, otherwise I see little point in adding map_while here instead of itertools.

scan can do everything... that not a good argument in this context.

@Stargateur
Copy link
Contributor

.take_while(|x| x.is_some())
.map(|x| x.unwrap());

@kamulos BY the way .take_while(|x| x.is_some()).flatten()

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Sep 18, 2021
@rfcbot
Copy link

rfcbot commented Sep 18, 2021

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

The RFC will be merged soon.

@rfcbot rfcbot added the to-announce Announce this issue on triage meeting label Sep 18, 2021
@matklad
Copy link
Member

matklad commented Sep 19, 2021

This method overall is very, very similar to scan.

scan and map_while are equivalent:

scan(init, |state, item| exr)

// is equivalent to

let state = &mut init;
map_whie(|item| expr)

map_while even is more general, as you can get the final state after the iteration is finished.

So, I'd say map_while is what we should have had from the begging, and scan is just an overly complicated version of that with an extra state argument, which makes sense in a purely functional language, but is unnecessary in Rust.

the8472 added a commit to the8472/rust that referenced this issue Sep 21, 2021
…le, r=kennytm

Stabilize `Iterator::map_while`

Per the FCP: rust-lang#68537 (comment)

This PR stabilizes `Iterator::map_while` and `iter::MapWhile` in Rust 1.57.
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Sep 24, 2021
@m-ou-se
Copy link
Member

m-ou-se commented Sep 29, 2021

Stabilized in #89086.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-iterators Area: Iterators B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. Libs-Small Libs issues that are considered "small" or self-contained Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests