How avoid (&*var).into()

I have a type DF { inner: DataFrame }. I also have a type Header<'a> that I can build from DataFrame.

My thought was I could build a Header by

  1. dereferencing df to point to my inner DataFrame
  2. call into specified in the From<DataFrame> for Header trait to produce the header value

This works using the following:

// where df: DF
let header: Header = (&*df).into();

Why doesn't it work using the following?

let header: Header = df.into()
impl Deref for DF
impl std::ops::Deref for DF {
    type Target = DataFrame;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}
impl From<&'a DataFrame> for Header<'a>
impl<'a> From<&'a DataFrame> for Header<'a> {
    fn from(df: &'a DataFrame) -> Self {
        Header::new(df.get_column_names())
    }
}

What are the From or Into and potentially Deref implementations you haven't mentioned?

Thank you for the follow-up. I updated the question to add those details.

Method resolution may be finding the blanket identity impl impl<T> From<T> for T { ... } and generating an error, rather than continuing through method resolution to find the deref impl. I've had issues similar to that before, but it's hard to tell without the error message.

1 Like

The error when I run df.into() is

The trait `From<DF>` is not implemented for `Header<'_>`

When I go ahead and implement From<&'a DF> for Header<'a> I don't need to deref df, but still need to (&df).into(). This seems like a "second" and redundant implementation. I'm happy to keep having to deref it manually in this particular scenario.

The benefit of Deref seems to end with a single lookup. I can get to inner but Rust won't type the inner value to lookup a trait from there?

Given obj: Ty, method resolution looks for receivers of type

  • Ty, &Ty, or &mut Ty
  • *Ty, &*Ty, or &mut *Ty
  • et cetera

So with df.into() it first looks for a method into(self: DF), and it finds that DF implements Into<T> for some T (if nothing else, itself) and stops the search.

You were wanting it to find into(self: &DataFrame), i.e. the &*Ty case, and that's the first thing it looks for when you do (&*df).into().

Here's some alternatives:

    // So you don't have to `(&*df).method()`
    let header = Header::from(&*df);
impl DataFrame {
    fn header(&self) -> Header<'_> {
        Header::from(self)
    }
}
// ...
    let header = df.header();

The latter works because the method resolution mentioned above continues on until the &*Ty case without finding any other header methods for the preceding potential receiver types.

1 Like

The code samples were helpful. I like how you chose to define a header method on DF to create the header.

When defining methods for DF (the parent), is there a convention in Rust to avoid depending on the DF implementation of Deref? (in which case I would use self.inner instead of self to access the inner DataFrame)?

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.