What is "impl Iterator" return type, and how might I pass it over FFI to be used from Swift

I'm getting there slowly I think, thanks again for all the help.

Let me see if I have this all right...

In my rust lib I'm returning iterator build from a channel's receiver. I don't want to expose that detail in my API. There are two(?) standard ways that I can hide this detail.

One ways is what I was doing, to return impl Iterator<Item = usize>. That works great for rust code calling other rust code. But it can't go over FFI boundary without using the indirection of a trait object, because only the rust compiler knows the actual type.

The other way is to wrap the iterator in a new type defined by my api. This also hides the underlying implementation, but can also go over FFI easily since I know the concrete type. But it's a little more work because my API needs a new public type, and needs code to expose the behavior (Iterator in this case) of the underlying type.

Here's what I'm doing now:

struct NumbersIterator(mpsc::IntoIter<usize>);

impl Iterator for NumbersIterator {
  type Item = usize;
  fn next(&mut self) -> Option<Self::Item> {
    self.0.next()
  }  
}

fn get_numbers() -> NumbersIterator {
  let (sx, rx) = mpsc::channel();
  sx.send(1);
  NumbersIterator(rx.into_iter())
}

Am I getting that about right?

1 Like

Essentially. You may also want to check out the FFI section in the nomicon, as it contains other information you might care about, given the fact you're writing an FFI.

1 Like

This is why I think that adding anonymous types without any zero-overhead way to name them was a mistake. If Rust had been designed with a little more care, we wouldn't have this situation in the first place.

In the mean time, the only option is to box things, or pray that you're not relying on a library which returns impl Foos.

The struct example above is a bit of an antipattern, which is an additional reason to remove the Box when possible. Keep in mind that impl Trait as it exists today is meant solely to make it easier to write function and method signatures without exposing implementation details. It is not (yet) meant to store in a user-definable type.

So essentially this not a case of a misdesigned feature per se, rather it is a matter of Rustaceans wanting more than the language currently is capable of offering.

I do however agree that it would be useful to have a 0-runtime overhead solution to storing impl Trait values in user defined places (structs, enums, locals etc).

The problem is that it is library authors that decide whether to use impl Trait in their APIs, but users who potentially need to store the returned values. So the whole purpose of impl Trait is to incentivize behavior which is bad for the ecosystem as a whole.

It is straight forward to avoid anonymous types in your own code, but when a library does it, you are completely out of luck.

1 Like

The flip side of this is that despite its power, in the real world impl Trait seems to be used mostly to hide concrete iterator types. And I don't tend to store Iterators in longer-lived objects, though that is partially because of the boxing overhead.

Thus the problem you describe is real and as I mentioned in my last response, it needs to be fixed, but it's probably not as big of a problem in practice as you make it sound.