Macro troubles, unsure why


#1

The following fails to compile, and I’m currently at a loss as to why.

pub struct Vec3<T> {
  pub x: T,
  pub y: T,
  pub z: T,
}

macro_rules! impl_vector {
  ($V:ident { $($field:ident),+ }) => {
    impl $V<f32> {
      pub fn squared_magnitude(&self) -> f32 {
        $(self.$field * self.$field)++
      }
    }
  }
}

impl_vector!(Vec3 { x, y, z });

I would expect this to expand to:

impl Vec3<f32> {
  pub fn squared_magnitude(&self) -> f32 {
    self.x * self.x+self.y * self.y+self.z * self.z
  }
}

#2

Your $( ... )++ is unfortunately getting parsed as $( ... )+ +. So it expands to self.x*self.x self.y*self.y ..., hence the error.

I’m not sure if that’s a bug or an expected behaviour, anyway, as a workaround you could just change it to $( ... + )+ 0.0


#3

That makes sense! Somehow it didn’t occur to me. Unfortunate.

The f32 was just a simplified example, 0.0 is not going to work on the end. But I could do this for now (using num_traits):

 impl<T: Copy + Mul<T,Output=T> + Add<T,Output=T> + Zero> $VecN<T>{
    #[inline]
    pub fn squared_magnitude(&self) -> T {
        $(self.$field * self.$field + )+ T::zero()
    }
}

#4

If you don’t want to use the Zero (although the Zero solution is perfectly fine), then you can also explicitly parse the first identifier: $first:ident $(, $field:ident)*, so you it serves you the purpose of the T::zero(). Also, maybe writing .add instead of + would work.