Are/Will boxable closures be possible with || syntax?


#1

Currently, I can do something like:

let mut c: Vec<Box<FnMut() -> uint + 'static>> = vec![];
c.push(box |&:| 1u);

and then by using the gated manual Fn traits:

struct Counter {
    count: uint,
}

impl FnMut() -> uint for Counter {
    extern "rust-call" fn call_mut(&mut self, (): ()) -> uint {
        let tmp = self.count;
        self.count += 1;
        tmp
    }
}

I am then able to do

c.push(box Counter { count: 5 });

To get something with explicit state.

I’ve tried to construct something that behaves similar to the Counter example, but uses closure notation rather than implementing the call directly. I haven’t been able to figure out a way of doing this. It seems to always either want to capture the environment by reference, which gives it a non-'static lifetime, or won’t capture it at all.

Is this something that is desired? I guess it feels natural to me, coming from functional languages, to be able to construct these types of closures. Or is the intent just to do the manual impl FnMut... to do this kind of thing?


#2

I guess the following is pretty much the same thing as your struct example:

let mut n = 5;
let mut c: Vec<Box<FnMut() -> uint + 'static>> = vec![];  // '
c.push(box move || {
    let tmp = n;
    n += 1;
    tmp
});

Note the move keyword, it is necessary to make the closure capture its environment by value.


#3

You should replace move || by |&mut:|. Otherwise you would only be able to call it once. (If I didn’t misunderstand something)

See: http://smallcultfollowing.com/babysteps/blog/2014/11/26/purging-> proc/

See this before asking about any other language change: https://github.com/rust-lang/rust/blob/master/RELEASES.md


#4

No, this is incorrect. move only affects capture semantics; calling semantics (&, &mut or by-value) are inferred. Because c is declared as a vector of boxes of FnMut() -> ..., the closure will be callable arbitrary number of times.


#5

I believe that using move will make the borrow checker complain.


#6

No, it won’t. There’s nothing to borrow here - the environment will be captured by value. I mean, I ran this code before posting, so I know it does not cause compilation errors)