Skip to content

Conversation

@phimuemue
Copy link
Member

In response to #283: I think we should employ a uniform architecture for our map-specializations (as they already diverged). This PR is meant to unify the implementations so we essentially only need to parametrize the mapping function:

  • Generalize MapInto to MapSpecialCase (which can be used as basis for all our map convenience functions) and define MapInto in terms of MapSpecialCase
  • Specialize collect (was specialized on MapOk, so I guess we want to keep it for now)
  • Define MapOk in terms of MapSpecialCase
  • Simple tests for specialized size_hint, fold, collect
  • As at this point probably all existing PRs involving map_xyz are conflicting anyway, move them to an own module (similar to coalesce)

@phimuemue phimuemue changed the title Map special Unify convenience map functions Jul 19, 2020

#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MapSpecialCase<I, F> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct MapSpecialCase<I, F> {
pub struct MapSpecialCase<I, F: ?Sized> {

This way unsized “special functions” can be used, including trait objects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation! Are unsized functions common? Alternatively, we could reverse the order of fields in MapSpecialCase and make I: ?Sized, thereby supporting iterator trait objects. (Unfortunately, it's one or the other.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this nice idea. In general, I am leaning to incorporate changes that generalize functionality.

However, I'd like to postpone this one and - if we decide to accept ?Sized functions - do it uniformly throughout itertools. I think my changes did not change behavior in this regard, so I hope postponing is ok.

@pthariensflame As I'm no expert in this area: Could you showcase a situation that requires F: ?Sized?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! If we have an unsized trait object dyn Fn(X) -> Y, then we get an unsized MapSpecialCaseFnOk<dyn Fn(X) -> Y>, which is then your example of an unsized F.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I'd like to postpone this one and - if we decide to accept ?Sized functions - do it uniformly throughout itertools. I think my changes did not change behavior in this regard, so I hope postponing is ok.

Fine by me!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pthariensflame I'm curious about the actual use-case dyn Fn might appear in. I've never needed to dynamically dispatched function objects before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm fine with waiting too. This isn't essential functionality, just mildly helpful at best.

As far as dyn Fn, I can't point to any specific code, but it might come up when abstracting over dynamically swappable actions. For example: imagine a pipeline of scriptable blocks that the user can specify in a GUI, and it gets compiled down to functions that invoke the scripts and munge the values flowing through as necessary. The whole pipeline is then composed and boxed up as a dyn Fn so that it can be altered on the fly as the application runs.

impl<I, R> Iterator for MapSpecialCase<I, R>
where
I: Iterator,
R: MapSpecialCaseFn<I::Item>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
R: MapSpecialCaseFn<I::Item>,
R: ?Sized + MapSpecialCaseFn<I::Item>,

impl<I, R> ExactSizeIterator for MapSpecialCase<I, R>
where
I: ExactSizeIterator,
R: MapSpecialCaseFn<I::Item>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
R: MapSpecialCaseFn<I::Item>,
R: ?Sized + MapSpecialCaseFn<I::Item>,

impl<I, R> DoubleEndedIterator for MapSpecialCase<I, R>
where
I: DoubleEndedIterator,
R: MapSpecialCaseFn<I::Item>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
R: MapSpecialCaseFn<I::Item>,
R: ?Sized + MapSpecialCaseFn<I::Item>,

}

#[derive(Clone)]
pub struct MapSpecialCaseFnOk<F>(F);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct MapSpecialCaseFnOk<F>(F);
pub struct MapSpecialCaseFnOk<F: ?Sized>(F);


impl<F, T, U, E> MapSpecialCaseFn<Result<T, E>> for MapSpecialCaseFnOk<F>
where
F: FnMut(T) -> U,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
F: FnMut(T) -> U,
F: ?Sized + FnMut(T) -> U,

pub fn map_ok<I, F, T, U, E>(iter: I, f: F) -> MapOk<I, F>
where
I: Iterator<Item = Result<T, E>>,
F: FnMut(T) -> U,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
F: FnMut(T) -> U,
F: ?Sized + FnMut(T) -> U,

@jswrenn
Copy link
Member

jswrenn commented Jul 21, 2020

This looks good to me!

bors r+

@bors
Copy link
Contributor

bors bot commented Jul 21, 2020

Build succeeded:

@bors bors bot merged commit 49e4880 into rust-itertools:master Jul 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants