Different behavior between `f.clone()` and `Arc::clone(&f)`

We constructed a case where Arc::clone(&f) and f.clone() behave differently due to type deduction – https://play.rust-lang.org/?version=stable&mode=debug... .

The gist of the issue is that some_function(f.clone()) works but some_function(Arc::clone(&f)) would fail to compile because it gets deducted to some_function(Arc::<dyn MyTrait>::clone(&f)) instead of some_function(Arc::<Foo>::clone(&f)).

I can't think of any reason why this type deduction precedence makes sense. Shouldn't the type of &f take precedence instead of the parameter type of some_function?

1 Like

If you like the clarity of Arc::clone but want to avoid the ::<…> part in some real code you have, note that you can “fix”[1] your call by adding a cast:

some_function(Arc::clone(&f) as _);

  1. by which I mean “adjust so the compiler accepts it” ↩︎

1 Like

What "should" and "shouldn't" happen is not necessarily what can (easily, or at all) be implemented by a compiler. In particular, the concurrent presence of 2 or more of {generics, coercions, subtyping/variance, context-dependent name resolution} is a Hard Problem.

You may find your expected operation "obvious", but it might just so happen that, for example, due to the particular implementation of type checking in the compiler, another, equally valid (from a technical rather than a usability PoV) sequence of type refinement operations happens, which results in the error above.

You might want to search for an existing issue, or if there is none, open your own, but it may not at all be easy to resolve.


Also note that this is — thankfully! — not different behavior of the code, which would be bad (silently changing types and potentially the behavior of their methods, just because you spelled "the same" clone method differently). If one incantation doesn't compile, then the only one that does remains unambiguous.

Furthermore, in this case, since there's an easy fix, I'd probably just use that (or stick to the nicer dot syntax) and call it a day.

Or Arc::<Foo>::clone(&f).[1]


  1. Though I too suggest just using .clone() for Arcs generally. ↩︎

1 Like

but it might just so happen that, for example, due to the particular implementation of type checking in the compiler

This is my guess as well but I would be interested to see a more concrete argument.

Especially if you consider the following compiles

let t = Arc::clone(&f);
some_function(t); // but not some_function(Arc::clone(&f));

Read the issue I linked.

1 Like

Ahh found it - Unsizing coercions apply in an inconvenient order with respect to constructor calls. · Issue #89299 · rust-lang/rust · GitHub. Thanks!

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.