If I understand it right, then a blanket implementation like in this other FIXME (note that the DerefMut
bound is missing there) would (in stable Rust) be incompatible with an implementation of AsMut<P> for P
for some type P
that is also DerefMut
(which includes AsMut<Vec<T>> for Vec<T>
).
Thus, while the first FIXME (for AsRef
and Deref
) could (theoretically, i.e. disregarding backward-compatibility) be implemented in stable Rust to create a consistent AsRef
implementation, doing that for AsMut
and DerefMut
would not work unless useful implementations like AsMut<Vec<T>> for Vec<T>
would be removed.
Of course, it would still be possible to manually add such "auto-dereferencing" implementations like in the FIXME for generic smart pointers such as Rc
, Arc
, etc. while providing a trivial implementation that just returns &mut self
for non-generic [1] smart pointers such as String
, Vec<T>
, etc.
I created a Playground to illustrate that:
/* … */
// This blanket implementation works fine
impl<T, U> MyAsRef<U> for T
where
T: ?Sized + MyDeref,
U: ?Sized,
<T as MyDeref>::Target: MyAsRef<U>,
{
fn my_as_ref(&self) -> &U {
self.my_deref().my_as_ref()
}
}
// This blanket implementation conflicts with the following 6 implementations
/*
impl<T, U> MyAsMut<U> for T
where
T: ?Sized + MyDerefMut,
U: ?Sized,
<T as MyDeref>::Target: MyAsMut<U>,
{
fn my_as_mut(&mut self) -> &mut U {
self.my_deref_mut().my_as_mut()
}
}
*/
// Would be covered by blanket implementation
impl<'a, T, U> MyAsMut<U> for &'a mut T
where
T: ?Sized + MyAsMut<U>,
U: ?Sized,
{
fn my_as_mut(&mut self) -> &mut U {
self.my_deref_mut().my_as_mut()
}
}
// Would be covered by blanket implementation
impl<T, U> MyAsMut<U> for Box<T>
where
T: ?Sized + MyAsMut<U>,
U: ?Sized,
{
fn my_as_mut(&mut self) -> &mut U {
self.my_deref_mut().my_as_mut()
}
}
// Would NOT covered by blanket implementation
// because `<String as Deref>::Target` is `str` and not `String`
impl MyAsMut<String> for String {
fn my_as_mut(&mut self) -> &mut String {
self
}
}
// Would be covered by blanket implementation
// because `<String as Deref>::Target` is `str`
// and `str` implements `AsMut<str>`
impl MyAsMut<str> for String {
fn my_as_mut(&mut self) -> &mut str {
self
}
}
// Would NOT covered by blanket implementation
// because `<Vec<T> as Deref>::Target` is `[T]` and not `Vec<T>`
impl<T> MyAsMut<Vec<T>> for Vec<T> {
fn my_as_mut(&mut self) -> &mut Vec<T> {
self
}
}
// Would be covered by blanket implementation
// because `<Vec<T> as Deref>::Target` is `[T]`
// and `[T]` implements `AsMut<[T]>`
impl<T> MyAsMut<[T]> for Vec<T> {
fn my_as_mut(&mut self) -> &mut [T] {
self
}
}
/* … */
This is just to experiment with these traits a bit to see what's possible to do without features like coherence-impacting negative bounds or specialization with the goal to get a better understanding for AsRef
and AsMut
, and to be able to deduce whether these features could help in future. Due to the conflicting implementations (that are all desirable), I assume that coherence-impacting negative bounds are not sufficient here, but that specialization is needed to provide such an "auto-dereferencing" blanket implementation for AsMut
(edit: under the premise that AsMut<String> for String
, AsMut<Vec<T>> for Vec<T>
, etc. shall be implemented).
I do not want to imply that any of this could currently (or even with specialization) be implemented, as it would break existent code anyway (if I understand it right, especially where .as_ref()
is used to dereference generic smart pointers as demonstrated in my previous post).
I tested whether the "auto-dereferencing" blanket implementation for AsMut
in combination with impl AsMut<String> for String
and impl<T> AsMut<Vec<T>> for Vec<T>
compiles with specialization, but it doesn't (Playground).
Vec<T>
in this context isn't entirely generic because even if being generic overT
it always points to a slice, i.e.Deref::Target = [T]
and notDeref::Target = T
. ↩︎