Why is boxing an iterator allowed?

This compiles:

fn a<'w,'z:'w,'y:'w>(x: (&'z [u32],&'y [u32])) -> Box<dyn Iterator<Item=&'w u32>+'w> {
    Box::new(x.0.into_iter())
}

But I thought we could not Box a Trait that has generic methods (E.g. map)

What makes this allowed for Iterators?

This is the definition of map:

fn map<B, F>(self, f: F) -> Map<Self, F>
where
    Self: Sized,
    F: FnMut(Self::Item) -> B,
{
    Map::new(self, f)
}

The key is where Self: Sized. This constraint says that map may not be called on dyn Iterator, which means that it isn't a problem that generic methods can't be implemented for dyn Iterator, because they can't be called.

The reason you can still call map on a boxed iterator is that Box itself implements the Iterator trait too, so you are calling it on the Box, not directly on the dyn Iterator inside the box.

18 Likes

Thank you so much. That is a nice trick.

You can also avoid boxing the iterator while remaining abstract if you return the result using a continuation rather than using regular output.

E.g. (the children function of the example trait)

pub trait Entity: std::fmt::Debug {
    fn as_any_ref(&self) -> &dyn Any;
    fn axes_op(&self) -> Option<Axes3D>;
    fn children<'a>(&'a self, k: &mut dyn FnMut(&mut dyn Iterator<Item=&'a dyn Entity>)) {
        k(&mut std::iter::empty())
    }
}

But I'm guessing in that you will loose the additional methods on it (like map). But nothing an additional wrapper can not fix, and the wrapper can also avoid heap allocation if it just carries a pointer to the internal iterator.

Edit: My bad, map also exists on a &mut dyn Iterator<...> because Iterator is also implemented for any &mut I where I is an iterator. Similar to the Box situation.

@LeisureBaker If you have a new question, open a new thread.

This was an attempt at spam. These particular spammers copy sentences from Reddit posts or other sources that show up in Google, so they can post messages that look relevant at first glance and don't trigger any spam filters. Then they go back later and edit their messages to include spam links. If you notice this sort of suspicious post from a user with little or no past activity, please flag it.

8 Likes