Futures-rs: [Question] why boxed() failed to compile.

Created on 19 Jan 2017  路  4Comments  路  Source: rust-lang/futures-rs

I write a test code which is a modified version of https://github.com/tokio-rs/tokio-line/blob/master/multiplexed/examples/echo_client_server.rs

Just few lines (see below) are replaced:

core.run(
    line::Client::connect(&addr, &handle)
        .map(Box::new)
        .and_then(|client| {
            let init = future::ok(client).boxed();
            (0..10).into_iter().fold(init, move |f, i| {
                f.and_then(move |client| {
                    client.call(format!("iter {}", i))
                        .map(move |response| {
                            println!("-> {:?}", response);
                            client
                        })
                })
                .boxed()
            })
        })
).unwrap();

What I want is send requests one by one after previous response back.

But this can not compiled,

error[E0277]: the trait bound `futures::Future<Error=std::io::Error, Item=std::string::String>: std::marker::Send` is not satisfied in `futures::AndThen<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`
  --> examples\echo_client_server.rs:51:22
   |
51 |                     .boxed()
   |                      ^^^^^ within `futures::AndThen<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`, the trait `std::marker::Send` is not implemented for `futures::Future<Error=std::io::Error, Item=std::string::String>`
   |
   = note: `futures::Future<Error=std::io::Error, Item=std::string::String>` cannot be sent between threads safely
   = note: required because it appears within the type `Box<futures::Future<Error=std::io::Error, Item=std::string::String>>`
   = note: required because it appears within the type `futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>`
   = note: required because it appears within the type `futures::future::chain::Chain<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`
   = note: required because it appears within the type `futures::AndThen<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`

It am very puzzled by this, and have no idea how to fix it. Could anyone here give my some help?

Most helpful comment

The whole as Box<Future<Item=Box<line::Client>,Error=::std::io::Error>> bit is terrifying, and I say this as somebody who thinks Rust is basically an easy and fun language, not a hard one. I would really need better error messages to be comfortable using tokio at work. Could the compiler help here in any way?

All 4 comments

I can get it to typecheck by switching from .boxed() to Box::new() (see this issue) and explicitly annotating the intended type for init:

core.run(
    line::Client::connect(&addr, &handle)
        .map(Box::new)
        .and_then(|client| {
            let init = Box::new(::futures::future::ok(client))
                as Box<Future<Item=Box<line::Client>,Error=::std::io::Error>>;
            (0..10).into_iter().fold(init, move |f, i| {
                Box::new(f.and_then(move |client| {
                    client.call(format!("iter {}", i))
                        .map(move |response| {
                            println!("-> {:?}", response);
                            client
                        })
                }))
            })
        })
).unwrap();

Note that the future you are constructing here will have size proportional to your iterator, which in this case has ten elements. A better approach might be to use loop_fn(), which would allow the loop to lazily unroll as it executes, maintaining a constant size independent of the number of elements in the iterator.

I believe @dwrensha was spot on, so closing. Thanks for the report though!

@dwrensha thank you very much. It is a very clear explaination.

The whole as Box<Future<Item=Box<line::Client>,Error=::std::io::Error>> bit is terrifying, and I say this as somebody who thinks Rust is basically an easy and fun language, not a hard one. I would really need better error messages to be comfortable using tokio at work. Could the compiler help here in any way?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

seanmonstar picture seanmonstar  路  4Comments

sile picture sile  路  5Comments

Matthias247 picture Matthias247  路  4Comments

xrl picture xrl  路  3Comments

MajorBreakfast picture MajorBreakfast  路  3Comments