Problems understanding moving Arc into closure


#1

Hello everyone,

I have code looking like this:

                "serve" => {
                    let sdb = Arc::new(Mutex::new(db));
                    let mut router = router::Router::new();
                    {
                        let sdb_ = sdb.clone();
                        router.get("/api/v1/records",
                                   move |req: &mut Request|
                                   handlers::get_records(sdb_.clone(), req));
                    }
                    {
                        let sdb_ = sdb.clone();
                        router.get("/api/v1/records/:id",
                                   move |req: &mut Request|
                                   handlers::get_record(sdb_.clone(), req));
                    }
                    {
                        let sdb_ = sdb.clone();
                        router.post("/api/v1/records",
                                move |req: &mut Request|
                                handlers::add_record(sdb_.clone(), req));
                    }
                    {
                        let sdb_ = sdb.clone();
                        router.put("/api/v1/records/:id",
                                   move |req: &mut Request|
                                   handlers::update_record(sdb_.clone(), req));
                    }
                    {
                        let sdb_ = sdb.clone();
                        router.delete("/api/v1/records/:id",
                                      move |req: &mut Request|
                                      handlers::delete_record(sdb_.clone(), req));

                    }

                    Iron::new(router).http("localhost:3000").unwrap();
                }

Now, I don’t get why I have to .clone the Arc twice:

                    {
                        let sdb_ = sdb.clone();
                        router.get("/api/v1/records",
                                   move |req: &mut Request|
                                   handlers::get_records(sdb_.clone(), req));
                    }

W/o it, if I do it like this

                    {
                        let sdb_ = sdb.clone();
                        router.get("/api/v1/records",
                                   move |req: &mut Request|
                                   handlers::get_records(sdb_, req));
                    }

I have this error.

Full example avaiiable here.

I’ve got several questions.

It doesn’t make sense to me: compiler tells the lifetimes are different but mentions the same lifetime requirements both times (cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements [E0495] error).

How cloning something affects whether it lives long enough or doesn’t?

Will non-lexical lifetimes fix this?


#2

The real error is “the trait (Fn) is not implemented for the type (closure)”: the way the closure is defined, it can only be called once. handlers::get_records consumes the Arc, so if you don’t clone it before passing it in, you can’t call the closure multiple times.

You might want to consider making get_records take an &Mutex<Connection> instead of an Arc<Mutex<Connection>>.


#3

This. I don’t see much of a need to have any of the code in handlers or afterwards be aware that Connection is stored in an Arc.

However, it might also be wise to use an RwLock instead of Mutex, as I believe these handler functions can be called in parallel. You don’t always need mutable access, looks like, but mutex synchronization means that only one thread can access Connection at a time, regardless of whether it’s reading or writing…


#4

Maybe no lifetimes you need… Look at this:

pub fn get_records(sdb: Arc<Mutex<Connection>> ....

You transfer owning into get_records, but closure already owns it. Use borrowing inside get_records:

pub fn get_records(sdb: &Arc<Mutex<Connection>>

or you have to clone referenced mutex every time.


#5

Is this for<'r, 'r, 'r> core::ops::Fn<(&'r mut iron::request::Request<'r, 'r>,)> syntax documented anywhere? Specifically, I don’t think I saw for<'r... before

the way the closure is defined, it can only be called once

How does one figure it out from the error?..

I’m actually aware of the suggested solution, sorry for not poiting it out earlier. I’m just trying to understand details and how to read the error messages: it bothers me I’m unable to understand and fix such errors w/o help from other people. /cc @DroidLogician


#6

Hm, and why can’t closure transfer ownership to get_records? sdb_ isn’t needed in the rest of the block.

But I’m cloning the Arc, not Mutex, am I?


#7

It’s because the function you pass to Router is Fn(...) -> ..., i.e. a shared immutable function. This means that any variables it closes over are accessed as &-references, so sdb_ inside closure is &Arc<...> and not Arc<...>. This is needed because router invokes that function multiple times. Otherwise, first call to closure would consume your Arc instance, and following calls will have no Arc to operate on. Think about closure as of object with invoke method, implicit self and some hidden fields.

UPD: try passing &Connection or &mut Connection to your handler funcs, and protect it with RWLock. This way you won’t need excess Arc clones.


#8

Oh, I start to get what’s going on.

One thing that is still not clear to me is how to figure it out from docs. All they say is it needs a Handler. How to know Handler is supposed to be Fn and not FnOnce?


#9
pub trait Handler: Send + Sync + Any {
    fn handle(&self, &mut Request) -> IronResult<Response>;
}

&self here tells you that router will be used via shared ref


#10

You are right, Arc clones:

fn clone(&self) -> Arc<T> {
        let old_size = self.inner().strong.fetch_add(1, Relaxed);
        if old_size > MAX_REFCOUNT { unsafe { abort(); } }
        Arc { _ptr: self._ptr }
    }

About closure specification:

pub trait Handler: Send + Sync + Any {
    fn handle(&self, &mut Request) -> IronResult<Response>;
}

Handler called as Fn (by immutable reference):

pub trait Fn<Args> : FnMut<Args> {
    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}

pub trait FnMut<Args> : FnOnce<Args> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

pub trait FnOnce<Args> {
    type Output;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

#11

The only what I don’t get is where do they have impl Handler for Fn


#12

Seems I found it:

    impl<F> Handler for F
    where F: Send + Sync + Any + Fn(&mut Request) -> IronResult<Response> {
        fn handle(&self, req: &mut Request) -> IronResult<Response> {
            (*self)(req)
        }
    }

#13

That’s true, and look for F, it required Fn, but with mutable request. Handler still not mut during handling, but in your case you’ve tried to take away owning :fishing_pole_and_fish: for its referenced mutex.


#14

for <'a> is the only syntax without docs. It’s a “higher ranked trait bound”, and is a very niche kind of thing. There’s an RFC that describes it. I haven’t figured out how/when to put it in the docs.