1

I've found this piece of code on a reddit post that is very confusing to me.

//We'll recurse all we want, thank you very much!
#![allow(unconditional_recursion)]

use std::ops::Deref;

#[derive(Debug)]
struct Outer<T: Deref<Target = Outer<T>>> {
    inner: T,
}

impl<T: Deref<Target = Outer<T>>> Deref for Outer<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

#[derive(Debug)]
struct Inner {}

impl Deref for Inner {
    type Target = Outer<Inner>;

    fn deref(&self) -> &Self::Target {
        //Look at which struct we're implementing Deref for,
        //and then read the next line very carefully.
        &self.inner
    }
}

const I: Inner = Inner {};
const O: Outer<Inner> = Outer { inner: I };

fn main() {
    println!("{:?}", O.inner);
    //Could just keep adding asterisks forever!
    println!("{:?}", *O.inner);
    println!("{:?}", **O.inner);
    println!("{:?}", ***O.inner);

    println!("{:?}", O);
    //Could just keep adding asterisks forever!
    println!("{:?}", *O);
    println!("{:?}", **O);
    println!("{:?}", ***O);
}

Specifically here:

impl Deref for Inner {
    type Target = Outer<Inner>;

    fn deref(&self) -> &Self::Target {
        //Look at which struct we're implementing Deref for,
        //and then read the next line very carefully.
        &self.inner
    }
}

How does the function return a reference to a field that belongs to another struct? Does &self actually refer to Outer here?

(Also this code crashes every time from stack overflow)

1 Answers1

1

Indeed there is no inner on Inner. But before giving up, the compiler thinks, "wait, is there some Deref implementation for Inner?" and of course the answer is, there is! We're writing it right now! So, what does it return? Outer<Inner>? Well, try to deref and find inner on Outer<Inner>! That is, &self.inner gets transformed into &<Self as Deref>::deref(&self).inner. That is autoderef in action.

Of course, since we are already inside <Inner as Deref>::deref(), we call it again, recursively... and again... and again... until we blow the stack. If you'll remove the #[allow(unconditional_recursion)] at the top, the compiler will warn you about that (playground):

warning: function cannot return without recursing
  --> src/main.rs:22:5
   |
22 |     fn deref(&self) -> &Self::Target {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
...
25 |         &self.inner
   |          ---------- recursive call site
   |
   = note: `#[warn(unconditional_recursion)]` on by default
   = help: a `loop` may express intention better if this is on purpose

But when you say #[allow(unconditional_recursion)], you tell the compiler "trust me, I know what I'm doing" so it just shrugs and continues.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77