How are users meant to understand futures errors?

#1

I’ve been loving rust and hating the futures API. It seems to be an endless trial-and-error-fest and the errors don’t help at all, so it’s mostly trial…

For example, right now I can’t finish one of my projects because of this bizarre error that doesn’t seem to make any sense in my existing knowledge of Rust syntax and the compiler:

error[E0271]: type mismatch resolving `<futures::stream::SplitSink<tokio::codec::Framed<std::boxed::Box<dyn websocket::async::Stream + std::marker::Send>, websocket::async::MessageCodec<websocket::OwnedMessage>>> as futures::Sink>::SinkError == ()`
  --> src/websocket_client.rs:60:31                                                                                                                                                             
   |                                                                                                                                                                                            
60 |                 outgoing_recv.forward(sink);                                                                                                                                               
   |                               ^^^^^^^ expected enum `websocket::WebSocketError`, found ()                                                                                                  
   |                                                                                                                                                                                            
   = note: expected type `websocket::WebSocketError`                                                                                                                                            
              found type `()`                                                                                                                                                                   

Why is the word forward the part it’s highlighting here? Where does it expect a websocket error? And where did it find ()? I’ve read the tokio/futures docs site more times than I can count, every time I think I understand combinators, I try and use them to do something seemingly simple and get hit with things like this.

Is there some special magic to reading and understanding these errors? Is this API even meant to be used right now?

The code in question is here:

If I can get this one last bit working with websockets, this project has completely been rewritten in Rust which is great because it’s much easier to dev/maintain/build/test/etc on different operating systems (the C++ one build broke for no apparent reason and wouldn’t fix, hence the rust rewrite…)

The architecture is simple, it’s just a couple of channels one writes to a websocket and the other reads values and places them in a queue which is then polled by the host application’s event loop.

I’d really appreciate some help getting this one over the finishing line, thanks!

#2

Hi, you’re not the only one struggling! So let’s take alook:

First thing to note (and this is not futures fault, but rustc’s): When it says expected xxx, found yyy the compiler means that the method or return type expected yyy but you gave it xxx.
yeah, duh, right.

So in your case you are producing enum websocket::WebSocketError where you should have a tuple.

as far as I can tell, the error type of your sink is enum websocket::WebSocketError where it should be a tuple.
websocket::async::MessageCodec<websocket::OwnedMessage>>> as futures::Sink>::SinkError == ()
This is probably the relevant part of the error message… So it’s the message codec which produces an error where futures wants a tuple.

#3

The () comes from here:

impl<T> Stream for Receiver<T>` 

type Item = T
type Error = ()

https://docs.rs/futures/0.1/futures/sync/mpsc/struct.Receiver.html

You can ignore the errors with:

outgoing_recv.forward(sink.sink_map_err(|_| ()));

(it’s a bit weird that it’s sink_map_err, not just map_err)

#4

Note specifically that it’s the SinkError that it’s complaining about (futures::stream::SplitSink<_>::SinkError == ()).

The Sink you’re getting from websocket is essentially a Sink<Item=websocket::OwnedMessage, Error=websocket::WebSocketError>.

What you’re currently doing is trying to forward items from a Stream<Item=T, Error=() to that sink, so the compiler is complaining that the error type of the stream is not the same as the error type of the sink.

I think you should be able to replace link 34 with

let sink = sink.sink_map_err(|_| ());

to map the sink error type to ().

#5

Thanks for the help, and especially thank you for explaining the stupid inverted error message @najamelan I hope that gets fixed - I assume this is because the type is being inferred based off my input which is then not matching the receiver which causes the inversion. The wording probably needs to be better to account for this case.

Anyway, now it’s building fine and I’ve hit an issue I thought I had resolved. Maybe worth opening another thread?

failed to send websocket data: send failed because receiver is gone

It seems the receiver is being dropped somehow, but it’s moved into the combinator closure so I don’t really understand where it’s being dropped.

#6

yeah, I think the diagnostics part of rustc needs some love. Unfortunately I don’t have much time to contribute to the compiler atm. I would love to get a focused effort on this. There are currently 792 issues with the A-diagnostics label, out of a total of +/-4500, aw and they degrade the user experience.

I must say I haven’t used websockets with tokio yet, so I couldn’t be of much help here, but I would say, websockets detect disconnection of the peer, so make sure you can catch disconnections in your program, and if that’s not it, I would try to trace back to where this error is coming from. If you can’t find it quickly, grep the source code of the libraries you use to see where this error comes from and take it from there.

good luck

#7

Ah this isn’t really related to the websockets, this is just an mpsc receiver getting dropped, but I’ll open a separate thread with more details anyway, thanks again :+1: