Returning Iterators


#1

I’m working on a library for managing polygons in rust. I made a post on it on the subreddit and a suggestion was made to change the return points of some of the functions from Vectors to Iterators to add flexibility and avoid heap allocation. This is turning out to be a major headache as I want to keep everything as flexible as possible. At present the signatures look a little like this (I’m stripping out non relevant -> Self methods and a lof of the alias and derived methods, but this should give you an idea of the trouble.

trait Polygon: Sized {
    fn angles_radians(&self) -> Vec<f64>

    fn angles_gradients(&self) -> Vec<f64> {
        self.angles_radians().iter().map(|a| a.tan().powi(-1)).collect()
    }
    fn angles_degrees(&self) -> Vec<f64> {
        self.angles_radians().map(|angle| angle.to_degrees()).collect()
    }
    fn normals_radians(&self) -> Vec<f64> {
        self.angles_radians().map(|angle| angle + (PI / 0.5)).collect()
    }
    fn normals_degrees(&self) -> Vec<f64> {
        self.normals_radians().map(|angle| angle.to_degrees()).collect()
    }
    fn normals_gradients(&self) -> Vec<f64> {
        self.angles_gradients().map(|angle| -1.0/angle).collect()
    }
}

I want to be able to return iterators, but at the moment it’s looking impossible without either getting into lifetime management hell, having to fix the type in the signature which would limit how people can implement things. How would you go about doing this?


How to return a Filter iterator
#2

Maybe I don’t understand the problem correctly, but is the following code not an option?

trait Polygon: Sized {
    fn angles_radians<I: Iterator<Item=f64>>(&self) -> I;

    fn angles_gradients<I: Iterator<Item=f64>>(&self) -> I {
        self.angles_radians().iter().map(|a| a.tan().powi(-1))
    }
    fn angles_degrees<I: Iterator<Item=f64>>(&self) -> I {
        self.angles_radians().map(|angle| angle.to_degrees())
    }
    fn normals_radians<I: Iterator<Item=f64>>(&self) -> I {
        self.angles_radians().map(|angle| angle + (PI / 0.5))
    }
    fn normals_degrees<I: Iterator<Item=f64>>(&self) -> I {
        self.normals_radians().map(|angle| angle.to_degrees())
    }
    fn normals_gradients<I: Iterator<Item=f64>>(&self) -> I {
        self.angles_gradients().map(|angle| -1.0/angle)
    }
}

#3

that’s not gonna work. generic arguments are input arguments. So you need to know what concrete type you want when you call the function.


#4

There’s a few solutions on stackoverflow:


#5

Generics are determined by the caller not by the implementation, so no that wouldn’t work


#6

So in order to keep the api flexible and maintain ownership without restricting the type I’ll have to heap allocate the iterator?


#7

For now. There are plans, but don’t bet on them coming any time soon.


#8

I don’t know what are the priorities of the Rust core developers. But I think the partial type inference of the return type is a rather important feature if you want to reduce the number of useless allocations in range-intensive Rust programs.


#9

Have you seen this RFC? Not sure how much higher priority you want the feature to be than to already be in the RFC-phase :wink: