Although i like how explicit the syntax is to implement operations for custom types, i think it can be quite unnecessarily verbose, an idea to fix that is to implement an attribute macro to do that for you, like this
struct Complex {
real: i32,
imaginary: i32,
}
impl Complex {
#[std::ops::Add(Complex)]
fn add(self, other: Complex) -> Complex {
Complex { real: self.real + other.real, imaginary: self.imaginary + other.imaginary }
}
#[std::ops::Sub(Complex)]
fn sub(self, other: Complex) -> Complex {
Complex { real: self.real - other.real, imaginary: self.imaginary - other.imaginary }
}
#[std::ops::Mul(Complex)]
fn mul(self, other: Complex) -> Complex {
Complex {
real: self.real * other.real - self.imaginary * other.imaginary,
imaginary: self.real * other.imaginary + self.imaginary * other.real,
}
}
#[std::ops::Div(Complex)]
fn div(self, other: Complex) -> Complex {
// TODO: implement
unimplemented!()
}
}
Something like that would be a lot nicer
1 Like
With some slight tweaks to the syntax, this could easily be a third party proc-macro crate:
struct Complex {
real: i32,
imaginary: i32,
}
#[bikeshed]
impl Complex {
#[bikeshed(std::ops::Add<Self>, Output = Self)]
fn add(self, other: Self) -> Self {
Self { real: self.real + other.real, imaginary: self.imaginary + other.imaginary }
}
#[bikeshed(std::ops::Sub<Self>, Output = Self)]
fn sub(self, other: Self) -> Self {
Self { real: self.real - other.real, imaginary: self.imaginary - other.imaginary }
}
#[bikeshed(std::ops::Mul<Self>, Output = Self)]
fn mul(self, other: Self) -> Self {
Self {
real: self.real * other.real - self.imaginary * other.imaginary,
imaginary: self.real * other.imaginary + self.imaginary * other.real,
}
}
#[bikeshed(std::ops::Div<Self>, Output = Self)]
fn div(self, other: Self) -> Self {
// TODO: implement
unimplemented!()
}
}
This doesn’t seem to save many, if any, keypresses, unless some nontrivial generics are involved (for those cases it would be nice to not have to repeat everything many times, though).
I’d rather like to see something like
impl Add + Sub + Mul + Div for Complex {
fn add/* … */
fn sub/* … */
/* or eg. fn Add::add… */
}
(You can already sort of do this by using a custom trait like Ring and blanket impls. There’s also the related nightly feature trait_aliases. The discussion on evolving trait hierarchies is also somewhat relevant.)
3 Likes
I like this idea. Helps similar traits get easily linked in implementation. But I would prefer something similar to the second syntax to avoid confusion.