Help to determine lifetimes for iterators
Help to determine lifetimes for iterators

ga_population.rs contains 2 new structs:

- GAPopulationRawIterator<'a, T: 'a + GASolution>
- GAPopulationFitnessIterator<'a, T: 'a + GASolution>

Each of them borrow the population they iterate over: population: &'a GAPopulation<T>

They also implement the Iterator trait and its next() method.

In ga_selectors.rs, the idea is to use the appropriate type of iterator according to the GAPopulationSortBasis used by the selector, by invoking a function of the selector’s GAScoreTypeBasedSelection trait object.

So the GAScoreTypeBasedSelection trait now has a function that returns an iterator:

fn iterator<'a>(&self, pop: &'a GAPopulation<T>) -> Box<Iterator<Item=&T>>;

and the structs that implement them, GARawScoreBasedSelection and GAScaledScoreBasedSelection, return the iterator that correspond to their type (GAPopulationRawIterator and GAPopulationFitnessIterator, respectively).

Notice that GAScoreTypeBasedSelection::iterator() returns a Box<Iterator<Item=&T>>. That’s because you can’t return an Iterator<Item=&T>, because it is a trait type and has no size. Box, on the other hand, has a size that’s known at compile time.

So:

- An iterator struct borrows a population.
- A GAScoreTypeBasedSelection trait object creates a Box that owns an iterator of the type that corresponds to it, and moves it to the caller.

Currently, only GARankSelect::select() (tries to) uses the iterator.

The error I get is:

ga_selectors.rs:101:56: 101:59 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495]
ga_selectors.rs:101         Box::new(GAPopulationRawIterator { population: pop, next: 0 } )
                                                                                                                        ^~~
ga_selectors.rs:99:5: 102:6 help: consider using an explicit lifetime parameter as shown: fn iterator<'a>(&'a self, pop: &'a GAPopulation<T>)
 -> Box<Iterator<Item = &T>>
ga_selectors.rs: 99     fn iterator<'a >(&self, pop: &'a GAPopulation<T>) -> Box<Iterator<Item=&T>>
ga_selectors.rs:100     {
ga_selectors.rs:101         Box::new(GAPopulationRawIterator { population: pop, next: 0 } )
ga_selectors.rs:102     }

As a side note, notice that selectors now own boxes of GAScoreTypeBasedSelection, rather than borrow them. On one hand, it simplifies code a little, because it allows us to remove the lifetime parameters that used to annotate the references they used to have (&GAScoreTypeBasedSelection). On the other hand, it doesn’t make much sense that each iterator own a GAScoreTypeBasedSelection that is stateless; when they used to be references, rather than boxes, we had the possibility of sharing a single GAScoreTypeBasedSelection with immutable references among multiple selectors.

One other thing I tried was to give ownership of the Iterator to the GAScoreTypeBasedSelection trait objects. It made sense, because each iterator had its own state, which reflected the current use that the GAScoreTypeBasedSelection object made of it. But again, lifetimes…

mrjackinc/rust-monster