Yes, this is usually so that the iterator can "generate" data as it goes, using some internal storage. And yeah, this needs a new trait. I don't think you could do it with the current Iterator
trait even if we had ATC. And certainly not backward compatibly.
This is sort of an interesting use case though. I hadn't thought it out before. So, imagine that we had this trait:
trait GenIterator {
type Item<'iter>;
fn next<'iter>(&'iter mut self) -> Self::Item<'iter>;
}
Obviously, this trait lets you do what you wanted to do. It has some kind of subtle effects, however, on people who want to write generic code over iterators. In particular, they can no longer assume that the data they produce will outlive the iterator (that is, indeed, the whole point!).
Now, one of the key things that the current iterator design supports is the ability to have one iterator trait supplying &T, &mut T, or T, as you need it (i.e., iter()
, iter_mut()
, and into_iter()
).
It is not entirely obvious whether ATC would also support that pattern. I haven't gotten to this part yet in the series, but one of the restrictions that we are considering for ATC (at least for now) is to limit how the lifetime/type parameters can be used. This would be to preserve forwards compatibility with an HKT-like system, if we want that. One part of these rules would be that every parameter must be used exactly once, and in the same order as they appear.
So for example, a definition like this would be disallowed:
impl GenIterator for vec::IntoIter<T> {
type Item<'a> = T; // illegal: `'a` is not used
}
But let's say we don't apply that restriction. In that case, the above iterator could work, so in a sense this iterator trait is strictly more expressive.
I was then starting to think about the generic functions that use the iterator trait. If you want to write a function that works over any iterator today, you might write:
fn first<I, T>(t: I) -> Option<T>
where I: Iterator<Item=T>
{
i.next()
}
What's kind of interesting about this is that the code above could be rewritten to use GenIterator
sort of like this:
fn first<I, T>(t: I) -> Option<T>
where I: GenIterator<Item<'iter>=T>
The key point here is that, because T
is bound outside of the scope of 'iter
, we know that if the where-clause is satisfied, I::GenIterator<'foo>
must not be dependent on 'foo
. Kind of interesting.
It'd be a good exercise to try and work out this example more, so as to see how generic adapters like Map
wind up looking. e.g., map normally takes a function F
where F: FnMut(Self::Iter)
, but it'd have to be something like F: for<'iter> FnMut(Self::Item<'iter>)
instead. I haven't tried to work this through to see if any problems arise.