Implictly convert `&Arc<closure>` to `&Arc<dyn Fn>`

I'm a little surprised that the compiler cannot automatically convert a between &Arc<closure> and &Arc<dyn Fn>:

fn test(f: &Arc<dyn Fn()>) {}


fn main() {
    test(&Arc::new(|| {}))
}

The error is:

error[E0308]: mismatched types
 --> src/main.rs:8:10
  |
8 |     test(&Arc::new(|| {}))
  |     ---- ^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
  |     |
  |     arguments to this function are incorrect
  |
  = note: expected reference `&Arc<(dyn Fn() + 'static)>`
             found reference `&Arc<[closure@src/main.rs:8:20: 8:22]>`
note: function defined here
 --> src/main.rs:4:4
  |
4 | fn test(f: &Arc<dyn Fn()>) {}
  |    ^^^^ -----------------

but it works fine by writing:

fn test(f: Arc<dyn Fn()>) {} // no reference here


fn main() {
    test(Arc::new(|| {}))
}

So why the reference type cannot be converted implicitly? And if I insist to using the first version of test, how to pass a closure easily? (Currently, I have to manually convert it to &Arc<dyn Fn()> by using as. And it needs to annotate the parameter version if the Fn take parameters.)

An Arc<closure> takes up 8 bytes because it consists of a pointer to the data inside the arc. An Arc<dyn Fn> takes up 16 bytes because it consists of a pointer to the data inside the arc and a pointer to the vtable for the function. You cannot make the conversion because the immutable reference is unable to modify the value it points at.

1 Like

Then why can I force convert it by using as?

You can use explicit type casting to cast Arc<closure> to Arc<dyn Fn()>, but not &Arc<closure> to &Arc<dyn Fn()>, as this is a non-primitive cast.

Note that you can also use placeholder typecasting:

fn test(f: &Arc<dyn Fn()>) {}

fn main() {
    test(&(Arc::new(|| {}) as _));
}
1 Like

Seems that I'd better to take a Arc rather than &Arc to give the user a better experience...

I'd say so, as Arc is a pointer itself and cheaply clonable.

I've hit the same problem with type inference and type coercion myself not long ago and I think it is related to your problem. I.e. the problem being that the compiler is unable to infer the right type as a trait object (dyn Fn() in this case) when we want to downcast a concrete type (the type of the closure in this example) implicitly.

You can find the topic here:

@quinedot and @steffahn wrote some very insightful posts in that topic IMO :slightly_smiling_face:

2 Likes

Also this post of mine in another topic should be relevant for illustration:

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.