Thanks for the replies all, I’ll try to address them all:
@Michael-F-Bryan Parameterizing Foo “leaks” the type of this iterator into the public interface where it really should be private - a holder of a Foo shouldn’t know or care about this detail of its non-public implementation. It also “pushes the problem up” - now the holder of Foo needs to figure out how to name this thing or elide it (which often isn’t a huge problem, but can be annoying e.g. if Foo itself is stored in something).
@jonh: I edited the original post to make it clearer that the value of the field is only ever the result of foo, not a publicly-settable value (i.e. it should always be the same type). The trade between generic structs and Box isn’t just whether I want runtime polymorphism - Box is easy to drop in and have it “just work”, without dealing with the viral spread of generic parameters to holders of Foo. Box lets me keep the type of the iterator encapsulated inside the module (where adding a generic parameter means changing code for most things that use Foo), but it’s odd that I have to add allocations and runtime costs to do that.
@vitalyd: True, I forgot that option. That’s what I have right now in playform/common/surroundings_loader.rs. Now that impl trait landed, I was hoping to replace it with something bjorn3 wrote in a PR:
fn surroundings_iter(center: Point3<i32>, max_distance: i32) -> impl Iterator<Item=Point3<i32>> {
(0 .. max_distance).flat_map(move |radius| cube_shell(¢er, radius))
}
Thanks all, I was curious if there were any new solutions to the problem of storing complicated iterators since impl trait landed, but it sounds like the same options as before.