Simple test case that fails with stack overflow:
// trait to say FnMut has a clone_box method
pub trait ClonableFnMut<A>: FnMut(A) {
fn clone_box(&self) -> Box<dyn ClonableFnMut<A> + Send + 'static>;
}
// overridden .clone() for Box<ClonableFnMut> that calls .clone_box on f
impl<A: 'static> Clone for Box<dyn ClonableFnMut<A> + Send + 'static> {
fn clone(&self) -> Self {
self.clone_box()
}
}
// .clone_box() on FnMut clones itself and wraps itself in a new Box
impl<A, F: FnMut(A) + Clone + Send + 'static> ClonableFnMut<A> for F {
fn clone_box(&self) -> Box<dyn ClonableFnMut<A> + Send + 'static> {
Box::new(self.clone())
}
}
fn main() {
let mut f: Box<dyn ClonableFnMut<u8> + Send + 'static> = Box::new(|_x|{});
println!("{:?}", f(3));
println!("{:?}", f.clone()(4));
}
Theoretically:
.clone() on Box<ClonableFnMut>..clone_box() on the inner FnMut.FnMut can now call .clone() on itself, since it's marked Clone..clone_box() returns this cloned FnMut (self) in a new BoxBut it actually:
.clone() manually on Box<ClonableFnMut>..clone_box() on inner Box<FnMut>.self.clone() which appears to mean self = box.Box<FnMut> clone() is called again, starts at step 1.What's the actual reason for step 4 happening?
The thing happening actually is slightly different:
clone on Box...clone_box on the same Box...clone on the same Box again, closing the loop.This happens because your implementation of Clone calls just self.clone_box(), but clone_box is a method of the ClonableFnMut trait. This trait is implemented, in particular, on Box<dyn ClonableFnMut<A> + Send + 'static> due to the blanket implementation, the requirements of which F: FnMut(A) + Clone + Send + 'static are satisfied by the Box itself.
To avoid this, you need to force the Clone implementation to call the clone_box method for the contents of the Box, not for the Box itself. There are two obvious ways in slightly different styles:
Replace self.clone_box() with self.deref().clone_box() and add the required import use std::ops::Deref; somewhere.
Alternatively, replace self.clone_box() with (**self).clone_box(), which does not require an extra import, but looks slightly cryptic. Note that the argument of clone, &self, is basically a syntactic sugar for self: &Self, so the first * dereferences it from &Box<F> to Box<F> and the second one dereferences it once more to F. Calling clone_box then auto-references it to &F as it requires &self too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With