8

I'm currently following along with https://raytracing.github.io/books/RayTracingInOneWeekend.html but I'm implementing everything in Rust. Here's a excerpt from my vector implementation:

type Scalar = f64; #[derive(Debug, Default, Clone)] pub struct Vector { x: Scalar, y: Scalar, z: Scalar, } impl Vector { fn new(x: Scalar, y: Scalar, z: Scalar) -> Self { Self { x, y, z } } fn x(&self) -> Scalar { self.x } fn y(&self) -> Scalar { self.y } fn z(&self) -> Scalar { self.z } } impl std::ops::Mul<&Vector> for &Vector { type Output = Scalar; fn mul(self, rhs: Self) -> Self::Output { self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() } } 

When I try to compile it, I get the following message:

error[E0308]: method not compatible with trait --> src/point.rs:33:5 | 33 | fn mul(self, rhs: Self) -> Self::Output { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&point::Vector, &point::Vector) -> _` found fn pointer `fn(&point::Vector, &point::Vector) -> _` note: the lifetime `'_` as defined on the impl at 30:20... --> src/point.rs:30:20 | 30 | impl std::ops::Mul<&Vector> for &Vector { | ^ note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 30:20 --> src/point.rs:30:20 | 30 | impl std::ops::Mul<&Vector> for &Vector { | ^ error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. error: could not compile `raytracing`. 

However, if I change the Self parameter on the mul function to &Vector, it compiles just fine:

[...] fn mul(self, rhs: &Vector) -> Self::Output { [...] 

Is this just a case where the lifetime inference fails? If so, why is it failing, since the compiler seems to have inferred everything correctly?

1 Answer 1

5

It's because of rule of lifetime elision, the error message tell it:

note: the lifetime '_ as defined on the impl at 30:20...

The line:

impl std::ops::Mul<&Vector> for &Vector { 

is interpreted as:

impl<'a, 'b> std::ops::Mul<&'a Vector> for &'b Vector // Self is &'b Vector 

and so lifetime mismatch because:

fn mul(self, rhs: Self) -> Self::Output { 

is

fn mul(self, rhs: &'b Vector) -> Self::Output { 

&'a Vector != &'b Vector so it's can't compile. Cause rhs should be &'a Vector.

When you use Self:

impl std::ops::Mul<Self> for &Vector { 

become:

impl<'a> std::ops::Mul<&'a Vector> for &'a Vector { 

so in fn mul(self, rhs: Self) -> Self::Output { rhs will have the correct lifetime <'a>

If a lifetime problem occurs try to be explicit to check if compiler get it wrong.

The final code should not contain any Self keyword to allow different lifetime:

impl std::ops::Mul<&Vector> for &Vector { type Output = Scalar; fn mul(self, rhs: &Vector) -> Self::Output { self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() } } 

explicit:

impl<'a, 'b> std::ops::Mul<&'a Vector> for &'b Vector { type Output = Scalar; fn mul(self, rhs: &'a Vector) -> Self::Output { self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() } } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.