Why is `AsMut<&mut Self>` not implemented for `Self`, i.e. any `T`?

Consider this code snippet:

use std::convert::AsMut;

#[derive(Debug)]
struct MyVec(Vec<i32>);

impl MyVec {
    
    fn push(&mut self, element: i32) {
        self.0.push(element);
    }
}

fn use_or_make<V: AsMut<MyVec>>(v: Option<V>) -> Option<MyVec> {
    if let Some(mut v) = v {
        v.as_mut().push(i32::default());
    } else {
        return Some(MyVec(vec![i32::default()]));
    };
    None
}

fn main() {
    let mut v = MyVec(vec![5]);
    let mut r = use_or_make(Some(&mut v));
    let mut v = {
        if r.is_some() {
            &mut (r.unwrap())
        } else {
            &mut v
        }
    };
    println!("{:?}", v);
}

Playground.

The error is:

Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `MyVec: AsMut<MyVec>` is not satisfied
  --> src/main.rs:24:29
   |
24 |     let mut r = use_or_make(Some(&mut v));
   |                 ----------- ^^^^^^^^^^^^ the trait `AsMut<MyVec>` is not implemented for `MyVec`, which is required by `&mut MyVec: AsMut<MyVec>`
   |                 |
   |                 required by a bound introduced by this call
   |
   = note: required for `&mut MyVec` to implement `AsMut<MyVec>`
note: required by a bound in `use_or_make`
  --> src/main.rs:13:19
   |
13 | fn use_or_make<V: AsMut<MyVec>>(v: Option<V>) -> Option<MyVec> {
   |                   ^^^^^^^^^^^^ required by this bound in `use_or_make`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 1 previous error

Basically, my question is simple, for all T, why doesn't Rust automatically implement AsMut<&mut T>?

Ideally, AsMut would be reflexive, i.e. there would be an impl<T: ?Sized> AsMut<T> for T with as_mut simply returning its argument unchanged. Such a blanket implementation is currently not provided due to technical restrictions of Rust’s type system (it would be overlapping with another existing blanket implementation for &mut T where T: AsMut<U> which allows AsMut to auto-dereference, see “Generic Implementations” above).

— AsMut in std::convert - Rust

5 Likes

I had actually read this and I apologize for not including this in my question. I don't understand what is meant by:

It would be good to have the “reflexive” impl you want,

impl<T> AsMut<T> for T
where
    T: ?Sized,

but it is not currently possible to have that impl and also have the “transitive” impl

impl<T, U> AsMut<U> for &mut T
where
    T: AsMut<U> + ?Sized,
    U: ?Sized,

and the standard library has made the trade-off of providing the second one and not the first one.

Note that BorrowMut made the opposite choice, it has the reflexive implementation but not the transitive one.

3 Likes

@SkiFire13

Thank you both for your sharing.

Would you go deeper into explaining why is it 'not currently possible' to have both implementations?

Thank you.

I got this from ChatGPT:

========== FROM CHATGPT ===========

In Rust, the two implementations you mentioned can’t coexist due to a conflict in how Rust’s trait system handles ambiguity when resolving method calls. Let’s break down why that happens.

The Implementations

Here are the two implementations in question:

  1. Reflexive implementation:

    impl<T> AsMut<T> for T
    where
        T: ?Sized,
    

    This implementation would allow any type T to convert itself to a mutable reference to itself (e.g., &mut T to &mut T).

  2. Transitive implementation:

    impl<T, U> AsMut<U> for &mut T
    where
        T: AsMut<U> + ?Sized,
        U: ?Sized,
    

    This allows a mutable reference to T (&mut T) to be converted to U as long as T implements AsMut<U>. This is useful for types where T can convert itself to U through AsMut.

Why Both Can't Coexist

The conflict arises due to how Rust resolves trait implementations when a type could match multiple implementations. Here’s the core issue:

  1. When using AsMut, Rust needs to determine which implementation to use. Suppose we have a type T, and we call as_mut on a mutable reference &mut T.

  2. With both implementations, there are two possible matches:

    • The reflexive implementation (impl<T> AsMut<T> for T) allows T to convert itself to T.
    • The transitive implementation (impl<T, U> AsMut<U> for &mut T) allows &mut T to convert to U if T: AsMut<U>.
  3. Rust’s trait system currently does not have a mechanism to disambiguate between these two implementations when both are available for the same type. Rust must be able to clearly decide which implementation to use, but in this case, it would face ambiguity for types where both could apply.

Trade-off Decision in the Standard Library

The Rust standard library has chosen to provide the transitive implementation because it’s more flexible and aligns with more use cases. The reflexive version, though intuitive, is less commonly required, and the transitive form adds a lot of power when working with complex types. Therefore, by design, only the transitive implementation is provided to avoid ambiguity and ensure predictable trait resolution.

This choice ultimately reflects a trade-off in favor of flexibility and versatility over consistency with the reflexive form.

========== END OF FROM CHATGPT ==========

Is its explanation accurate?

My follow up question would then be, why can't we specify which trait we want to use using the as keyword? e.g. <T as AsMut<U>>::as_mut(t);

And in this Playground, I can also implement AsMut<MyVec> for MyVec, it doesn't clash with anything else. Why is that so?

Also, for libraries that have types that are 'container-like', i.e. they hold certain states within themselves, e.g. Vec<T> holding some numbers of T, and these types have mutable methods that mutate its internal state, should the library authors of these types implement AsMut<LibraryType> for LibraryType?

Note: I didn't read your ChatGPT dump.[1]


The trait solver wants to find one applicable implementation. Given this function:

fn foo<W>() where &mut W: AsMut<&mut W> {}

Both blanket implementations would apply. Fully qualified paths (<T as AsMut<U>>) don't help:

  • They just signal the implementing type and trait, not which implementation
  • Fully qualified paths are an expression syntax, not a bound syntax, anyway

See also this blog post. (See the AsRef sections, which is in the same situation as AsMut.)

Negative reasoning is utilized for local types. But not foreign ones. And there's no "local type generic parameter".


  1. Arguably it's not allowed on this forum, BTW. ↩︎

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.