[RFC] Automatically insert relational overloading based on existing
For example, if we have custom eq we can always defina ne(a, b) as !eq(a, b) implicitly but only if operator marked as "private":
class Vec2 {
constructor(public x: f64 = 0, public y: f64 = 0) {}
@operator("==")
private eq(other: f64): bool {
return this.x == other.x && this.y == other.y;
}
// automatically define "ne" by compiler:
// @operator("!=")
// private ne(other: f64): bool {
// return !this.eq(other);
// }
}
similar to > / <= and < / >=:
class Vec2 {
constructor(public x: f64 = 0, public y: f64 = 0) {}
@operator(">")
private gt(other: f64): bool {
return this.x > other.x && this.y > other.y;
}
@operator("<")
private lt(other: f64): bool {
return this.x < other.x && this.y < other.y;
}
// automatically define "le" by compiler:
// @operator("<=")
// private le(other: f64): bool {
// return !this.gt(other);
// }
// automatically define "le" by compiler:
// @operator(">=")
// private ge(other: f64): bool {
// return !this.lt(other);
// }
}
In this case we can define minimal set to ==, > and < to define full comparison domain. The rest can be overload optionally if behavior for !=, <=, >= should be different
One initial thought perhaps: Operator overloads are relatively unrestricted, i.e. an eq is not required to return a bool, respectively a == is not guaranteed to be an equals check at all. Would that lead to problems?
Yeah. Result type should be a bool. Good point!
But now I'm wondering should we restrict overloadings ==, != and etc to always be a bool as a result?
Maybe a new operator overload is helpful <=>
similar as cpp https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison
I think for most of case it's enough. eq / le / ge fulfills mathematical requirement.
The code should be like:
class Vec {
constructor(public x: f64 = 0, public y: f64 = 0) {}
norm2(): f64 {
return this.x * this.x + this.y * this.y;
}
// @operator("<=>")
private threeWayCmp(other: Vec): i32 {
const thisNorm2 = this.norm2();
const otherNorm2 = other.norm2();
return thisNorm2 - otherNorm2;
}
// automatically define by compiler:
@operator("==")
private eq(other: Vec): bool {
return this.threeWayCmp(other) == 0;
}
@operator("!=")
private ne(other: Vec): bool {
return this.threeWayCmp(other) != 0;
}
@operator(">")
private ge(other: Vec): bool {
return this.threeWayCmp(other) > 0;
}
@operator("<=")
private nge(other: Vec): bool {
return this.threeWayCmp(other) <= 0;
}
@operator(">")
private le(other: Vec): bool {
return this.threeWayCmp(other) < 0;
}
@operator("<=")
private nle(other: Vec): bool {
return this.threeWayCmp(other) >= 0;
}
}
Maybe a new operator overload is helpful <=>
It is not as universal as it may seem. For example, it won't work for unsigned int and floating points. Or rather, you will have to do rather non-trivial things to make it work. You can check it out here
What I mean is just adding a decorator @operator("<=>") instead of adding a total new operator. The aim is that by this decorator, we don't need to write lots of similar compare code. It just a syntactic sugar.
Of course, your suggestion is more flexible but I think self-defined >= <= == without mathematical meaning is very corner case.
it won't work for unsigned int and floating points I do not get the point why this design won't work for them.