Reputation:
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?
Upvotes: 3
Views: 111
Reputation: 1206
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.
Upvotes: 2