If you need to return a point/vector you can explicitly use the constant version (for members) or mutable points if you don't care (i.e. local variables).
I would actually just use the base class for returning members. Again, this is sacrificing perfect safety for performance, but this isn't an unusual pattern in Java.
I think you can save yourself some work and maintenance burden by dropping all the methods from Point2cd other than those defined in Tuple2d. We should be encouraging the use of the mutable type for calculations anyway (performance) - they'ld be better off just converting a Point2cd to a Point2md and working from there, since every action will be creating new objects anyway. This would then suggest that Point2cd would only be used for instantiation, and the result always stored in a Point2d.
Here are some use cases around how I would see the types being used, which may be useful to discuss:
1. Constants - Would instantiate as Point2cd and store as Point2d. Guarantees immutability.
Code:
public static final Point2d ONE = new Point2cd(1, 1, 1);
public void doingSomeCalculation() {
Point2md a = ...;
...
a.add(ONE);
}
2. Field - return as Point2d. While this doesn't guarantee immutability, it doesn't expose the mutability so the consumer is breaking contract by casting and changing it. If you really wanted to be sure and performance wasn't a consideration, you could copy it into a new Point2cd, but you would still return it as a Point2d.
Code:
private Point2md value = new Point2md(1, 2, 3);
public void setValue(Point2d newVal) {
value.set(newVal);
}
public Point2d getValue() {
return value;
}
3. Doing a calculation (note, favor returning Point2md because it is a new value anyway, and the user can make use of it however they like):
Code:
public Point2md calculate(Point2d v1, Point2d v2, ...) {
Point2md result = new Point2md(v1).add(v2).mult(v3);
return result;
}
or a more general pattern for performance, allowing you to populate an existing Point2md:
Code:
public Point2md calculate(Point2d v1, Point2d v2, ...) {
return calculateInto(new Point2md(), v1, v2, ...);
}
public Point2md calculateInto(Point2md result, Point2d v1, Point2d v2, ...) {
return result.set(v1).add(v2).mult(v3);
}
Basically, I don't think Point2cd would come up to often, and even when it did you would probably just instantiate it and store as a Point2d. So you might as well save yourself some effort and keep it simple.
Some really picky thoughts around names, sorry:
- Perhaps the mutable implementation could be called Vector2d. It is the main thing that will be instantiated and used, so it should have the simple, clear name. (It would be nice to avoid alphabet soup names)
- The interface then would be Point2d perhaps - or Tuple2d?
- The constant implementation could be Point2dConst/Tuple2dConst/ConstantTuple2d? Basically, I don't think the c or m are particularly clear. The longer name is fine in this case because you wouldn't generally have variables of that type, just instantiate it and store it in a Point2d.