Deref trait of type is ignored in other trait implementations

Hallo,
i have tried to implement a struct which should mimick the behaviour of Box<T> (mostly, Box is special and cannot be implemented by hand (there is no DerefMove trait)...).

I implemented the Deref, DerefMut trait and the Display trait, but it creates a recursion if I try to dereference &self in the Display trait. I'm not sure why this happens, but it looks like the Deref trait is ignored.

Sidenote: My test struct does not allocate data on the heap in contrast to Box<T>.

My code first:

struct ABox<T> {
    val: T
}
use std::{
    ops::{
        Deref, DerefMut
    }
};
impl<T> Deref for ABox<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.val
    }
}
impl<T> DerefMut for ABox<T> {
    fn deref_mut(&mut self) -> &mut T{
        &mut self.val
    }
}
impl<T: std::fmt::Display> std::fmt::Display for ABox<T> where ABox<T>: Deref {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&(*self), f) // fail: Creates a recursion (maybe because the Deref trait is not respected by the compiler?)!
    }
}

fn main() {
    let a = ABox{val:123};
    println!("{}", a);
}

I'm not sure why this happens. Shouldn't the Deref trait make sure, that *self is resolved to T, so that &(*self) resolves to &T not &ABox<T>? Currently it looks like the deref operator does not respect the existence of the Deref trait.

self here is &Self. So *self is Self and &(*self) is &Self, which means you're calling the same function. To avoid it use &**self instead.

https://doc.rust-lang.org/stable/src/alloc/boxed.rs.html#1434-1438

1 Like

Or better yet, use the UFCS to specify exactly which function you want

impl<T: std::fmt::Display> std::fmt::Display for ABox<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        <T as std::fmt::Display>::fmt(self, f)
    }
}
4 Likes

This does not compile: <ABox<T> as Deref>::Target cannot be formatted with the default formatter, the trait std::fmt::Display is not implemented for <ABox<T> as Deref>::Target

Thats weird because in this example T is a i32 and I'm sure it implements Display :slight_smile:

What does *Self do? Does it dereferene to the real type, in this case &ABox<T>?

That does not compile: expected reference &T, found reference &ABox<T>

Remove the where ABox<T>: Deref constraint in the Display impl or modify it to ABox<T>: Deref<Target = T>

1 Like

That's it. both &**self or <T as std::fmt::Display>::fmt works now. Why does this constraint produces this error (it makes no sense to me) and what does it mean to dereference self twice? Is *Self = &ABox<T>?

The constraints take precedence over implementations. And since you didn't specify the associated type, Rust can't see that it's always T

1 Like