Closures being passed as args multiple times?

I'm trying to implement a sort of 'select' function for a quad tree implementation similar to what you'd find in SQL. It takes a predicate (Fn I believe covers both closures and functions?) and what it's supposed to do is iterate through a vector of items it has and evaluate the predicate for each, then the 'select' function is supposed to recursively call itself on an array of child nodes and evaluate the predicate on each of them.

The problem is that closures cannot copy nor clone. How would I pass a closure as an argument multiple times?

1 Like

You'd pass a reference to the closure.

..... there goes my 4am logic again. I should ask during the day I think.

I realize this is an old thread but not too many people will be notified and it's exactly what I'm stuck with.

How do you handle this in a case where the closure needs to be 'static, e.g. for passing to FFI (in particular wasm)?

Well, these days, closures do now impl Copy and Clone when possible. If your closure doesn't impl Clone, then that must be because it takes something from the environment that doesn't impl Clone. Try putting that thing into an Rc.

1 Like

Ah ok cool... got some other problems to juggle but that does solve this, thanks!

@dakom for an answer illustrating this fact with examples, see Closures don't move? - #2 by Yandros

EDIT: actually you are the OP of that thread, so of course you already knew it :sweat_smile:

This is indeed the general pattern to make any 'static closure be cheaply Cloneable (instead of giving Copy-es of &f, let's "give Clones of Rc::new(f)"). It should be noted, however, that Rc<impl Fn()> : !Fn(), so a little trick is needed to get reference-counting cloning and the Fn() callable interface:

use ::std::{
    ops::Deref,
    rc::Rc,
};

fn main ()
{
    // non-Copy closure (it owns s: String which is not Copy)
    let f = {
        let s = String::from("Hello, World!");
        move || {
            println!("{}", s);
        }
    };

    fn challenge (f1: impl Fn() + 'static, f2: impl Fn() + 'static)
    {
        f1();
        f2();
    }

    // Attempt 1
    // let at_f = &f;
    // challenge(at_f, at_f); // Error, not 'static
    
    // Attempt 2
    // let at_f_static = Rc::new(f);
    // challenge(at_f_static.clone(), at_f_static); // Error: Rc<_> does not impl Fn
    
    let f = {
        let at_f_static = Rc::new(f);
        move || {
            at_f_static.deref()()
        }
    };
    challenge(f.clone(), f);
}
1 Like

LOL... oh man... I really need to go back through this forum and re-read and/or consolidate all the questions I've asked and answers I've been given...

Prediction: I'll be asking this question again in another month or three...

1 Like