Tuple operations and traits

From the std libary documentation:

If every type inside a tuple implements one of the following traits, then a tuple itself also implements it:
Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash

Is there a reason why the same is not true for traits like:

  • Zero, One
  • Neg, Not
  • Add, Sub, Div, Mul, Rem (and their *Assign counterparts)
  • BitAnd, BitOr, BitXor (and their *Assign counterparts)
  • Shl, Shr (and their *Assign counterparts)
  • Drop

I fail to see why we couldn't have:

let a: (X, Y, Z) = (x0, y0, z0);
let b: (X, Y, Z) = (x1, y1, z1);
assert_eq!(a + b, (x0 + x1, y0 + y1, z0 + z1));

and possibly for homogeneous tuples:

let a: (X, X, X) = (x0, x1, x2);
let n: X = x;
assert_eq!(a * n, (x0 * x, x1 * x, x2 * x));
1 Like

Probably not for any specific reason. Possibly for the sake of simplicity. This may be some RFC material.

Drop is a special case and there is no reason to implement it if no explicit destructor is required.

I don't think it's a good idea to implement mathematical operators on tuples. You think it should be element-wise, but others may think e.g. multiplication should be like with mathematical vectors. There's special vectors implementing your operations for small tuple sizes in the vecmath and the nalgebra crates. You should be using them explicitly instead of relying on magic behavior of tuples.

Wrt Zero and One, yea, those should be there. As @ogeon notes, Drop is implicitly implemented for all types (just try it out, put an object that implements Drop in a tuple and drop the tuple).

1 Like

Yeah, my bad for Drop @ogeon I didn't really think that one through.

Regarding the other traits, I hardly see that as magical. The tuple is not required to be homogeneous, the elements don't even have to be numbers; they could be strings, or vectors themselves, or a local type. I'm talking in a much more general sense.

Also, vector product is a very special case that can't apply to any type: the tuple must be homogeneous, elements must be numbers, and although I imagine one would use * in rust, since we can't define infix functions with arbitrary names like ^, the elements would have to implement more than just Mul which actually makes * unfit.

Additionally, I can't make a blanket implementation locally myself because of the orphan rule I believe, which means that operations can't be used at all on tuples. That's kind of a waste.

The only solutions are either to declare a new type or to explicitly repeat the operation on all the elements of both tuples. Not always very neat IMO.

Please correct me if I'm wrong.

A new type is the clean way to describe it. A coordinate pair that can be added and subtracted is a Point2<T> and so on.

In my particular case, I am not talking about a coordinate pair. I have unrelated values, that must simply be treated in parallel.

Hmm, forwarding Zero to each tuple element is probably fine in general, but you can also get by with Default. I doubt there's a good interpretation for One though -- for instance, I would not expect a unit vector to be (1, 1).