Evaluate if statement to a trait object without boxing

Is there a way to resolve a branching statement, like an if, to a trait object without boxing, or are there plans to allow this?

My situation is this, I want to conditionally filter an iterator if I have Some(pos), otherwise I want to use the original iterator, then I want to consume the iterator in a while loop:

while let Some((pattern_index, pos_sub)) = if let Some(pos) = pos {
	parent.positions.iter().filter(|(_, pos_sub)| *pos_sub == pos)
} else {
	parent.positions.iter()
}.next() {
    ...
}

Here I get the error:

`if` and `else` have incompatible types

expected struct `std::iter::Filter`, found struct `std::collections::hash_set::Iter`

So a solution is to collect the iterator into a vector:

let candidates: Vec<_> = if let Some(pos) = pos {
    parent.positions
          .iter()
          .filter(|(_pattern_index, pos_sub)| *pos_sub == pos)
	      .collect()
} else {
	parent.positions.iter().collect()
};
while let Some((pattern_index, pos_sub)) = candidates.iter().next() {
    ...
}

or I could box the trait object and access that

let candidates: Box<dyn Iterator<Item=_>> = if let Some(pos) = pos {
	Box::new(parent.positions.iter()
          	.filter(|(_pattern_index, pos_sub)| *pos_sub == pos))
} else {
	Box::new(parent.positions.iter())
};
while let Some((pattern_index, pos_sub)) = candidates.next() {
    ...
}

But it seems like the compiler could figure that out by itself and permit the if statement to return different types, as long as the result only uses trait items common to both results.

let foo;
let bar;
let trait_impl: &dyn Trait = if test {
    foo = Foo {};
    &foo
} else {
    bar = Bar {};
    &bar
};

You could use that trick maybe ?

5 Likes

Use the either crate, either::Either implements Iterator

let candidates: Vec<_> = if let Some(pos) = pos {
    Either::Left(parent.positions
          .iter()
          .filter(|(_pattern_index, pos_sub)| *pos_sub == pos))
} else {
	Either::Right(parent.positions.iter())
};
2 Likes

Oh, cool! Perfect, exactly what I was looking for.

The solution with either actually helped me in another case where the trait object did not work, because the iterator also had to be Sized. So thanks a lot for mentioning it.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.