24

A FnMut closure cannot be cloned, for obvious reasons, but a Fn closure has an immutable scope; is there some way to create a "duplicate" of a Fn closure?

Trying to clone it results in:

error[E0599]: no method named `clone` found for type `std::boxed::Box<std::ops::Fn(i8, i8) -> i8 + std::marker::Send + 'static>` in the current scope
  --> src/main.rs:22:25
   |
22 |             fp: self.fp.clone(),
   |                         ^^^^^
   |
   = note: self.fp is a function, perhaps you wish to call it
   = note: the method `clone` exists but the following trait bounds were not satisfied:
           `std::boxed::Box<std::ops::Fn(i8, i8) -> i8 + std::marker::Send> : std::clone::Clone`

Is it safe to somehow pass a raw pointer to a Fn around, like:

let func_pnt = &mut Box<Fn<...> + Send> as *mut Box<Fn<...>>

Technically, the above works, but it seems quite weird.

Here's an example of what I'm trying to do:

use std::thread;

struct WithCall {
    fp: Box<Fn(i8, i8) -> i8 + Send>,
}

impl WithCall {
    pub fn new(fp: Box<Fn(i8, i8) -> i8 + Send>) -> WithCall {
        WithCall { fp: fp }
    }

    pub fn run(&self, a: i8, b: i8) -> i8 {
        (self.fp)(a, b)
    }
}

impl Clone for WithCall {
    fn clone(&self) -> WithCall {
        WithCall {
            fp: self.fp.clone(),
        }
    }
}

fn main() {
    let adder = WithCall::new(Box::new(|a, b| a + b));
    println!("{}", adder.run(1, 2));

    let add_a = adder.clone();
    let add_b = adder.clone();

    let a = thread::spawn(move || {
        println!("In remote thread: {}", add_a.run(10, 10));
    });

    let b = thread::spawn(move || {
        println!("In remote thread: {}", add_b.run(10, 10));
    });

    a.join().expect("Thread A panicked");
    b.join().expect("Thread B panicked");
}

playground

I have a struct with a boxed closure in it, and I need to pass that struct to a number of threads. I can't, but I also can't clone it, because you can't clone a Box<Fn<>> and you can't clone a &Fn<...>.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Doug
  • 32,844
  • 38
  • 166
  • 222
  • What would you like to do with the cloned closure? – Shepmaster Jan 11 '15 at 02:55
  • What's your full code? – huon Jan 11 '15 at 03:06
  • @shepmaster I specifically want to clone a closure without mutable state to move it into multiple tasks at the same time. See the example I've attached. – Doug Jan 11 '15 at 03:57
  • 1
    "you can't clone a &Fn<...>". You [can](https://github.com/rust-lang/rust/blob/431105a70acaf6e0a1d64b6dd3f69563d6694287/src/libcore/clone.rs#L46), specifically the `?Sized` there means it works with trait objects. – huon Jan 11 '15 at 04:18
  • @dbaupp Box::new(*(&(*self.fp)).clone()) -> error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn(i8, i8) -> i8 + Send` – Doug Jan 11 '15 at 04:28
  • That's due to all the dereferencing that is happening, not the `&Fn()` clone directly. I expect the same error message will occur without the `.clone()`. – huon Jan 11 '15 at 04:31

3 Answers3

14

Rust 1.26

Closures implement both Copy and Clone if all of the captured variables do. You can rewrite your code to use generics instead of a boxed trait object to be able to clone it:

use std::thread;

#[derive(Clone)]
struct WithCall<F> {
    fp: F,
}

impl<F> WithCall<F>
where
    F: Fn(i8, i8) -> i8,
{
    pub fn new(fp: F) -> Self {
        WithCall { fp }
    }

    pub fn run(&self, a: i8, b: i8) -> i8 {
        (self.fp)(a, b)
    }
}

fn main() {
    let adder = WithCall::new(|a, b| a + b);
    println!("{}", adder.run(1, 2));

    let add_a = adder.clone();
    let add_b = adder;

    let a = thread::spawn(move || {
        println!("In remote thread: {}", add_a.run(10, 10));
    });

    let b = thread::spawn(move || {
        println!("In remote thread: {}", add_b.run(10, 10));
    });

    a.join().expect("Thread A panicked");
    b.join().expect("Thread B panicked");
}

Before Rust 1.26

Remember that closures capture their environment, so they have a lifetime of their own, based on the environment. However, you can take references to the Fn* and pass those around further, or store them in a struct:

fn do_more<F>(f: &F) -> u8
where
    F: Fn(u8) -> u8,
{
    f(0)
}

fn do_things<F>(f: F) -> u8
where
    F: Fn(u8) -> u8,
{
    // We can pass the reference to our closure around,
    // effectively allowing us to use it multiple times.
    f(do_more(&f))
}

fn main() {
    let val = 2;
    // The closure captures `val`, so it cannot live beyond that.
    println!("{:?}", do_things(|x| (x + 1) * val));
}

I would say that it is not universally safe to convert the Fn* to a raw pointer and pass it around, due to the lifetime concerns.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    Shep, `WithCall` doesn't actually do anything; [you can clone without it](https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=e4c25b0514959a406be2a37a348da6a7). There is nothing stopping `F: Fn(i8) -> i8` supporting `Clone`. But trying cloning a `Box i8>`; I [don't think](https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=079dd5feef12c99932f65bc4b852c712) it's (safely) possible! – dhardy Nov 21 '18 at 14:59
  • 2
    @dhardy yes, it's not *needed*, but it exists to mirror OPs original structure where they had a type containing a closure, not just a closure. The fact that you can `derive(Clone)` on it shows that closures are clonable, which is also what my first sentence tries to convey: *Closures implement both `Copy` and `Clone` if all of the captured variables do*. And no, [you cannot clone a boxed trait object because `Clone` is not object safe](https://stackoverflow.com/q/30353462/155423). – Shepmaster Nov 21 '18 at 15:03
  • 1
    So there is simply no way to copy an `Fn(...)` trait object? Of course `&Fn(...)` is `Copy` but this comes with lifetime restrictions. – dhardy Nov 21 '18 at 15:13
12

What you are trying to do is call a closure from multiple threads. That is, share the closure across multiple threads. As soon as the phrase "share across multiple threads" crosses my mind, my first thought is to reach for Arc (at least until RFC 458 is implemented in some form, when & will become usable across threads).

This allows for safe shared memory (it implements Clone without requiring its internal type to be Clone, since Clone just creates a new pointer to the same memory), and so you can have a single Fn object that gets used in multiple threads, no need to duplicate it.

In summary, put your WithCall in an Arc and clone that.

use std::sync::Arc;
use std::thread;

type Fp = Box<Fn(i8, i8) -> i8 + Send + Sync>;

struct WithCall {
    fp: Fp,
}

impl WithCall {
    pub fn new(fp: Fp) -> WithCall {
        WithCall { fp }
    }

    pub fn run(&self, a: i8, b: i8) -> i8 {
        (self.fp)(a, b)
    }
}

fn main() {
    let adder = WithCall::new(Box::new(|a, b| a + b));
    println!("{}", adder.run(1, 2));

    let add_a = Arc::new(adder);
    let add_b = add_a.clone();

    let a = thread::spawn(move || {
        println!("In remote thread: {}", add_a.run(10, 10));
    });
    let b = thread::spawn(move || {
        println!("In remote thread: {}", add_b.run(10, 10));
    });

    a.join().expect("thread a panicked");
    b.join().expect("thread b panicked");
}

playground


Old answer (this is still relevant): It is quite unusual to have a &mut Fn trait object, since Fn::call takes &self. The mut is not necessary, and I think it adds literally zero extra functionality. Having a &mut Box<Fn()> does add some functionality, but it is also unusual.

If you change to a & pointer instead of an &mut things will work more naturally (with both &Fn and &Box<Fn>). Without seeing the actual code you're using, it's extremely hard to tell exactly what you're doing, but

fn call_it(f: &Fn()) {
    (*f)();
    (*f)();
}

fn use_closure(f: &Fn()) {
    call_it(f);
    call_it(f);
}

fn main() {
    let x = 1i32;
    use_closure(&|| println!("x is {}", x));
}

(This is partly due to &T being Copy and also partly due to reborrowing; it works with &mut as well.)

Alternatively, you can close-over the closure, which likely works in more situations:

fn foo(f: &Fn()) {
    something_else(|| f())
}

A FnMut closure cannot be cloned, for obvious reasons.

There's no inherent reason a FnMut can't be cloned, it's just a struct with some fields (and a method that takes &mut self, rather than &self or self as for Fn and FnOnce respectively). If you create a struct and implement FnMut manually, you can still implement Clone for it.

Or is it safe to somehow pass a raw pointer to a Fn around, like:

let func_pnt = &mut Box<Fn<...> + Send> as *mut Box<Fn<...>>

Technically the above works, but it seems quite weird.

Technically it works if you're careful to ensure the aliasing and lifetime requirements of Rust are satisfied... but by opting in to unsafe pointers you're putting that burden on yourself, not letting the compiler help you. It is relatively rare that the correct response to a compiler error is to use unsafe code, rather than delving in to the error and tweaking the code to make it make more sense (to the compiler, which often results in it making more sense to humans).

Community
  • 1
  • 1
huon
  • 94,605
  • 21
  • 231
  • 225
  • Sorry, that was a bit of a rubbish question. I've updated it with an example of what I'm trying to do. Closing over a closure might be a solution, but I'm not sure on how you'd do it. – Doug Jan 11 '15 at 03:58
  • @Doug, yes, questions without the actual source are extremely difficult to answer in a useful way. Updated. – huon Jan 11 '15 at 04:31
  • @dhardy huon isn't saying that you can clone a `&mut T` but that you can clone a struct that has a *function* that accepts a `&mut T`: *and a **method** that takes `&mut self`*. – Shepmaster Nov 21 '18 at 15:06
  • @dhardy *there's no reason an `Arc` should be necessary* — that's covered by [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/q/32750829/155423). An `Arc` is indeed needed for `std::thread` because ownership is given to the thread. – Shepmaster Nov 21 '18 at 15:07
  • @Shepmaster I was assuming the cloned function might be called on the *same* data, but of course cloning an `FnMut` clones the data too so huon is correct. (I deleted my previous comment because SO won't let me correct it now, and there's no need to leave incorrect information here.) – dhardy Nov 21 '18 at 15:45
0

Here is the working code in 1.22.1

The intent is to make this work.

let x = |x| { println!("----{}",x)};

let mut y = Box::new(x);

y.clone();

The original code as suggested at the top was used.

I started with cloning a Fn closure.

type Fp = Box<Fn(i8, i8) -> i8 + Send + Sync>;

Ended up adding Arc around Fp in the struct WithCall

Play rust : working code Gist : working code in 1.22.1