Functions that return impl, has to be always the same underlying type?

I have a function with an impl return type:

fn myfn(myparam: i64) -> impl Stream<Item = Result<Bytes, Box<dyn std::error::Error + 'static>>> 

But it seems I can return only one type that satisfies the impl. So this doesn't work:

  if myparam == 5 {
    start
      .chain(sync_users)
      .chain(system_user)
      .chain(znstream)
      // .chain(anstream)
      .chain(als)
      .chain(ls)
      .chain(end)
  } else {
    start
      .chain(sync_users)
      .chain(system_user)
      .chain(znstream)
      .chain(anstream)
      .chain(als)
      .chain(ls)
      .chain(end)
  }

So its returning pretty much a stream in either case, but with one less Chain<>. Both branches of the if would satisfy the impl, but its true they are different types underneath.

I can understand why this is the way it is, but its also kind of inconvenient. Any chance this will change in the future?

It's conceivably possible if we get something like compiler-provided anonymous trait-forwarding enums. If so, it's a long ways off though.

If Either supports your trait you can use that[1] (but Stream isn't a std trait so probably it doesn't).

There are sometimes hacky ways around it... like you could have

// (The `Stream` equivalent of...)
.chain([anstream].into_iter().flatten()) 

in one branch and

.chain([].into_iter().flatten())

in the other, so they have the same type.


  1. recursively for more than two variants ↩︎

3 Likes

The futures crate has its own for this:

5 Likes

The futures create also offers nice convenience methods for constructing these, .left_stream() and .right_stream().

So your code might work by simply adding these like

if myparam == 5 {
    start
      .chain(sync_users)
      .chain(system_user)
      .chain(znstream)
      // .chain(anstream)
      .chain(als)
      .chain(ls)
      .chain(end)
      .left_stream()
  } else {
    start
      .chain(sync_users)
      .chain(system_user)
      .chain(znstream)
      .chain(anstream)
      .chain(als)
      .chain(ls)
      .chain(end)
      .right_stream()
  }
2 Likes

Another possibility would be polymorphic generics.

Both are “something we may get in Rust 2042 if we are lucky”.

Not something topicstarter may hope to wait for to solve his immediate problem.

Yet another solution is #[auto_enum], which could be what compiler support would look like.

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.