# Inconsistency: deref coercion doesn't work

**URL:** <https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157>\
**Category:** language design\
**Created:** [October 21, 2019, 3:24am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157 "2019-10-21T03:24:55Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![lihzhang](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lihzhang/32/6160_2.png) [@lihzhang](https://internals.rust-lang.org/u/lihzhang)\
**Post date:** [October 21, 2019, 3:24am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/1 "2019-10-21T03:24:55Z")

</div>

```rust
struct S;
trait T {
    fn method(&self) -> &'static str {
        "T"
    }
}
impl S {
    fn method(&self) -> &'static str {
        "S"
    }
}
impl T for S {}

fn main() {
    let b = Box::new(S);
    assert_eq!(b.method(), "S");
    assert_eq!(S::method(&b), "S");

    // Error: the trait `T` is not implemented for `std::boxed::Box<S>`
    // but deref coercion should work here.
    assert_eq!(T::method(&b), "T");
}

```

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [October 21, 2019, 3:45am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/2 "2019-10-21T03:45:34Z")

</div>

Coercions only work if there is no type inference involved, when you say `T::method(&b)` you are really saying `<_ as T>::method(&b)`, so it won't apply _any_ coercions (not just deref coercions). This is consistent with the rest of the language.

---

<div class="post-metadata">

**Author:** ![lihzhang](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lihzhang/32/6160_2.png) [@lihzhang](https://internals.rust-lang.org/u/lihzhang)\
**Post date:** [October 21, 2019, 3:53am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/3 "2019-10-21T03:53:05Z")

</div>

What is the particular reason why coercions only work if there is no type inference involved?

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [October 21, 2019, 3:56am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/4 "2019-10-21T03:56:06Z")

</div>

Because coercions play badly with type inference, and can lead to some very confusing code. This was an explicit decision to prevent some very weird bugs.

For example, if I added

```rust
impl<U: T + ?Sized> T for Box<U> {
    fn method(&self) -> &'static str {
        "Box<_>"
    }
}

```

Then the behavior of your program would suddenly change, all because of the interaction between coercions and inference. Changes like these lead to code that is harder to maintain.

---

<div class="post-metadata">

**Author:** ![lihzhang](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lihzhang/32/6160_2.png) [@lihzhang](https://internals.rust-lang.org/u/lihzhang)\
**Post date:** [October 21, 2019, 4:16am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/5 "2019-10-21T04:16:42Z")

</div>

I think this is how coercions work, weird or convenient. There are some restrictions like "only traits defined in the current crate can be implemented" or "can't impl for type defined outside of crate". It seems there is not a big chance to accidentally cause some confusing problems.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [October 21, 2019, 4:23am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/6 "2019-10-21T04:23:38Z")

</div>

Let's say an upstream crate adds a new implementation (which is entirely possible), this could change the semantics your code just by updating dependencies. (now there are other ways this could happen, but adding a new implementation seems like the sort of thing that won't affect old code, so this is particularly insidious)

---

<div class="post-metadata">

**Author:** ![lihzhang](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lihzhang/32/6160_2.png) [@lihzhang](https://internals.rust-lang.org/u/lihzhang)\
**Post date:** [October 21, 2019, 7:48am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/7 "2019-10-21T07:48:38Z")

</div>

Thank you for your wisdom. After `impl T for dyn Deref<Target = S> {}`, can't still compile. Why is this?

```rust
trait T {
    fn method(&self) {}
}
struct S;

impl T for dyn std::ops::Deref<Target = S> {}

fn main() {
    let b = Box::new(S);

    // Error: the trait `T` is not implemented for `std::boxed::Box<S>`
    T::method(&b);
}

```

---

<div class="post-metadata">

**Author:** ![lihzhang](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lihzhang/32/6160_2.png) [@lihzhang](https://internals.rust-lang.org/u/lihzhang)\
**Post date:** [October 21, 2019, 8:04am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/8 "2019-10-21T08:04:50Z")

</div>

```rust
trait T {
    fn method(&self) {}
}
struct S;

impl S {
    fn method(&self) {}
}

impl T for S {}

fn main() {
    let b = Box::new(S);

    // auto deref is safe, because `impl &S` is invalid.
    S::method(&b);

    // Error: unsafe to auto deref,
    // because `impl T for &S` or `impl T for Box<S>` is possible.
    T::method(&b);
}

```

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [October 21, 2019, 8:30am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/9 "2019-10-21T08:30:03Z")

</div>

There is a distinction between two steps here: coercions and function lookup. Coercions only apply when the input and output types are known, after which function to call has been determined. Function lookup is a separate process that [_during method calls_ looks through possible deref impls and unsized coercions](https://doc.rust-lang.org/nightly/reference/expressions/method-call-expr.html) to determine which function is called.

For a normal function call there is no lookup happening, it will look for _exactly_ which function you attempted to call (which is why this was known as "Unambiguous Function Call Syntax"). In this case it sees you attempting to call `<S as _>::method(&Box<S>)`, which is not a function that currently exists, but by adding `impl T for Box<S> {}` it will. (UFCS isn't actually unambiguous, as far as I know there's no way to force the method to be an inherent method).

---

<div class="post-metadata">

**Author:** ![lihzhang](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lihzhang/32/6160_2.png) [@lihzhang](https://internals.rust-lang.org/u/lihzhang)\
**Post date:** [October 21, 2019, 9:45am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/10 "2019-10-21T09:45:02Z")

</div>

Thank you for your informative explanation. If the input and out types are known, can coercions apply to pattern matching? It can't for now.

```rust
struct S {
    a: i32,
    b: i32,
}
fn matching(S { a, b }: &S) {}

fn main() {
    let b = Box::new(S { a: 0, b: 0 });
    matching(&b); // this is cool.

    // Error: expected struct `std::boxed::Box`, found struct `S`
    let S { a, b } = &b;
}

```

---

<div class="post-metadata">

**Author:** ![sanxiyn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sanxiyn/32/8824_2.png) [@sanxiyn](https://internals.rust-lang.org/u/sanxiyn)\
**Post date:** [October 21, 2019, 10:29am UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/11 "2019-10-21T10:29:13Z")

</div>

That works. Try `let S { a, b } = *b;` instead.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [October 21, 2019, 2:07pm UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/12 "2019-10-21T14:07:40Z")

</div>

> [@Nemo157](#):
>
> (UFCS isn't actually unambiguous, as far as I know there's no way to force the method to be an inherent method).

If Rust has to pick bwtween an inherent method and a trait method, it will always pick the inherent method.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [October 21, 2019, 2:16pm UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/13 "2019-10-21T14:16:22Z")

</div>

Yes, but you can't write something that will either call an inherent method or fail to compile. For example if you have an inherent method being called via UFCS masking a trait method, when you delete that inherent method it will just fall back to calling the trait method. Whereas you _can_ use UFCS to refer to a method defined by a specific trait, and if that trait is no longer implemented for the type it will fail to compile instead of finding a similarly named method on a different trait/inherent impl.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [October 22, 2019, 8:22pm UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/14 "2019-10-22T20:22:11Z")

</div>

> [@Nemo157](#):
>
> Yes, but you can't write something that will either call an inherent method or fail to compile.

You kind of can ... [but it is not pretty](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8dccc504c6f09f3f3a3a643adae20135) 😅

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [January 20, 2020, 8:30pm UTC](https://internals.rust-lang.org/t/inconsistency-deref-coercion-doesnt-work/11157/15 "2020-01-20T20:30:00Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
