Nested Function Calls

This is a small pet peeve of mine. It's probably a duplicate, because I couldn't figure out how to properly spell out my question.
I have the following code:

Impl From<u8> for StructName {
  fn from(value: u8) -> Self {
    return Self::from(value as i8);
  }
}

(obviously an example)
if I call the function from with a u8, will the compiler inline the function and just make it an implicit type cast?
I tried figuring this out with Godbolt but I cannot find a proper way to not make the compiler just optimize everything else around it.

That's probably fine, but you could add #[inline].

2 Likes

There was a recent change to the compiler that automatically enables cross-crate inlining for “small” functions. And in general, you should expect that functions like this will almost always be inlined within one crate.

However, it is still a reasonable plan to add #[inline] to them to be sure, for functions like this one which will predictably be able to be compiled to just a few instructions. Just don't overdo it and #[inline] everything, because inlining is not a magic “make everything faster” button (if it were, the compiler would do it always for you).

When trying to test this sort of thing, write a public, non-generic function that has appropriate parameters and return value to exercise the code you want to see. That way, the compiler is obligated to actually generate machine code for the signature you specified. For example, test_function in this code:

pub struct StructName(i32);

impl From<i8> for StructName {
  fn from(value: i8) -> Self {
    return Self(i32::from(value));
  }
}
impl From<u8> for StructName {
  fn from(value: u8) -> Self {
    return Self::from(value as i8);
  }
}

pub fn test_function(value: u8) -> StructName {
    StructName::from(value)
}

compiles to:

<example::StructName as core::convert::From<i8>>::from::h4be375ce75b903f6:
        movsx   eax, dil
        ret

which is one instruction just as we might hope. (The reason the function label in the assembly is for From::from and not test_function is that test_function, <StructName as From<i8>>::from, and <StructName as From<u8>>::from actually compile to identical machine code, so the output only has one copy of it, and it gets labeled with an arbitrary one of the 3 functions.)

In this particular case, you don't need the test_function as the impls will work by themselves, but writing an explicit test function is a good general technique for convincing the compiler to actually generate code for you to look at.

3 Likes

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.