Implementing constructors: does it matter if return explicit type or Self?

I was going through some code on GitHub and noticed something that looks strange to me.

// line: 65
pub const fn new(addr: u32) -> Self {
    Self {
        ptr: addr as *mut T,
    }
}

// Line: 187
pub const fn new(mask: $t, shift: $t) -> RegisterField<$t> {
    Self {
        mask: mask,
        shift: shift,
    }
}

// Line 211
pub const fn new(field: RegisterField<$t>, value: $t) -> Self {
    RegisterFieldValue {
        field: field,
        value: value & field.mask //<< field.shift
    }
}

All of these constructors define return types differently (either type, either Self) and return differently as well. I wonder if it has any specific meaning or no. Is it as should be or just not sticking to the same coding style?

Yes, this is just a code style difference. There is some discussion around a clippy lint for it: https://github.com/rust-lang/rust-clippy/issues/1190

1 Like

I typically recommend using Self for the return type, because you risk doing this:

impl<'a> MyType<'a> {
    fn new() -> MyType { // oops, forgot <'a>
        ...
    }
}

If you forget the lifetime parameter here, it's automatically elided into a different type than you intended.

7 Likes

Is it? I've just checked it myself and got a compile error: playground.

Ok fair enough, but if any of the arguments have a reference, then eliding does happen.

Hey thanks for looking into one of my crates :slight_smile:
As this was one of my early attempts to write macros and the like I might overlooked the fact that I’m using different styles while progressing the learning... Have put this to my “todo bucket” and will clean up the code in the upcoming versions.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.