Skip to content

[Question] why boxed() failed to compile. #363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
hh9527 opened this issue Jan 19, 2017 · 4 comments
Closed

[Question] why boxed() failed to compile. #363

hh9527 opened this issue Jan 19, 2017 · 4 comments

Comments

@hh9527
Copy link

hh9527 commented Jan 19, 2017

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?

@dwrensha
Copy link
Contributor

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.

@alexcrichton
Copy link
Member

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

@hh9527
Copy link
Author

hh9527 commented Jan 20, 2017

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

@emk
Copy link

emk commented Jan 20, 2017

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants