Distinguishing affine and vector quantities in the type system

I don't know whether Rust's current const generics would make this nice, but you could try out something I'll call "compile-time homogeneous coordinates".

It'd be something like this:

struct Homogeneous<T, const W: isize>([T; 3]);
type Point<T> = Homogeneous<T, 1>;
type Vector<T> = Homogeneous<T, 0>;

Then you have

impl<T, const W1: usize, const W2: usize> Add<Homogeneous<T, W2>> for Homogeneous<T, W1> {
    type Output = Homogeneous<T, W1 + W2>;
    ...
}
impl<T, const W1: usize, const W2: usize> Sub<Homogeneous<T, W2>> for Homogeneous<T, W1> {
    type Output = Homogeneous<T, W1 - W2>;
    ...
}

That means you can do p1 + p2 - p3 and still get a Point as it should be, without needing to p1 + (p2 - p3) to fit the intermediate types into what you've defined. Similarly, it'd be fine to Neg a point, it just would give you something distinct from both Points and Vectors, but if you added another Point to it you'd get back to a Vector.

It also has the nice advantage that you don't need to write separate Sub impls for Point-Point, Point-Vector, and Vector-Vector, since they all just work and do the thing you wanted.

(I assume someone else has thought of this before, but I've not actually seen it.)

7 Likes