Cloning an enum containing a closure


#1

I’m working on a Goal-Oriented Action planning technique like in this paper, in which the API for an action planner allows the user to provide “procedural conditions.” The planner moves between States, and States are made up of Aspects. The value of an Aspect can be True, False, a string, or a function that returns a boolean based on other aspects. To model this, I have an AspectValue enum that looks like the following:

pub enum AspectValue {
    True,
    False,
    String(String),
    Closure(Box<Fn(State)->bool>),
}

I need to be able to clone AspectValues, but am receiving the trait std::clone::Clone is not implemented for dyn std::ops::Fn(State) -> bool. From what I’ve read, cloning closures should be allowed as of a few versions ago. I’ve made a playground example where I tried to create a minimal example with the problem.

Is there a syntax to make this work, or is there a more rusty approach?


#2

Have you tried defining the Closure variant as the following :

Closure(Box<dyn Fn(State) -> bool + Clone>)

This forces the contents of the box to implement Clone.

Ps. it’s newer syntax to say dyn Trait as opposed to Trait
Edit:
Oops, I got the typing wrong… Refer to @KrishnaSannasi’s post about function pointers.


#3

This won’t work playground

i.e. you can’t us arbitrary constraints as a trait object. Also, Clone is not object safe


#4

Do you need closures? Or will normal functions suffice. If so you could just use a function pointer, fn(State) -> bool (note the lowercase fn). Function pointers are Clone and Copy.

#[derive(Clone)]
pub enum AspectValue {
    True,
    False,
    String(String),
    Closure(fn(State) -> bool),
}

If not you will have to go the route of generics.

#[derive(Clone)]
pub enum AspectValue<F: Fn(State) -> bool> {
    True,
    False,
    String(String),
    Closure(F),
}

#5

Function pointers seem to work just fine on the playground, and I don’t think I’m giving up any flexibility. I didn’t realize how big the difference between Fn and fn was. I have to go brush up on the exact differences. Thanks!


#6

With function pointers you can’t capture variables in the surrounding scope and are Sized, those are the only differences compared to Fn. Closures coerce into function pointers if you don’t capture anything from the surrounding scope.


#7

The ability to coerce is really cool. I didn’t notice that when I was playing around earlier, since I wasn’t capturing any variables.