- The example you gave at the bottom won't really work, because enum variants aren't fully-fledged types on their own and they can't impl `Future`. Therefore, you can't `.await` them on their own. Furthermore, the point of `try_join` is to poll both futures until one fails, which you can't do with `async` syntax.
- Rust requires that you spell out all generic parameters like this at function boundaries. It's technically possible to infer types across such boundaries, but that has the potential for significant changes to the typing of a function to go entirely unnoticed. In fact, I believe some of Rust's documentation specifically calls out problems Haskell had with inferring function signatures like this.
That being said, you are correct that we could do this instead:
```pub fn try_join<FutureA, FutureB, ValueA, ValueB, Error>(future_a: FutureA, future_b: FutureB> -> impl Future<Output = Result<(ValueA, ValueB), Error> where FutureA: Future<Output = Result<ValueA, Error>>, FutureB: Future<Output = Result<ValueB, Error>>,```
That is slightly more readable.