Trait function returning Result of Iterator


#1

Hi guys,

I have the following trait:

pub trait Query {
    type Reply;
    fn query(&self) -> Result<Iterator<Item=Self::Reply>, String>;
}

The intent is for the query method to return a sequence of replies (hence the Iterator type) and should allow for failure (hence the Iterator wrapped in Result). However it does not compile:

 the trait bound `std::iter::Iterator<Item=<Self as Query>::Reply> + 'static: std::marker::Sized` is not satisfied
  --> src\main.rs:13:9
   |
13 |         fn query(&self) -> Result<Iterator<Item=Self::Reply>, String>;
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=<Self as Query>::Reply> + 'static`
   |
   = note: `std::iter::Iterator<Item=<Self as Query>::Reply> + 'static` does not have a constant size known at compile-time
   = note: required by `std::result::Result`

This makes sense. I understand that Result needs to know the size of the enclosed item at compile time.

However, what I want to know is what is the best way to fix the problem. One approach I can think of is to make query() function generic over a type T and apply the Sized constraint to T like below:

pub trait Query {
    type Reply;
    fn query<T: Sized+Iterator<Item=Self::Reply>> (&self) -> Result<T, String>;
}

But I’m afraid this will make the trait more painful to use. My specific concern is that anyone who uses it will also have to be generic over T. Is that concern justified?

Perhaps another alternative is to use a Box, i.e. return a Result<Box<Iterator<Item=Reply>>, String>, but this is a tiny bit less attractive performance-wise.

Please suggest the best way.


#2

You’re right here. I guess you want to the query function to decide which will be the iterator type, not the caller.

If you don’t want to pay the performance penalty of the Box, you can use add another associated type here:

pub trait Query {
    type Reply;
    type Iter: Iterator<Item=Self::Reply>;
    fn query(&self) -> Result<Self::Iter, String>;
}

#3

Thanks krdln. This is probably the most sensible approach.

Another option I probably have is return a reference to the iterator, i.e. Result<&Iterator<Item=Self::Reply>, String>, but what you suggested looks like the most flexible way from the implementer’s perspective.