1

Say that I have an immutable Point class with x and y parameters, and an add method defined like this:

class Point:
  Point add(int x, int y):
    return new Point(this.x + x, this.y + y);

Since it's immutable, it returns a new Point. This is all well and good until we have a class that extends Point and redefines add.

class ColoredPoint extends Point:
  ColoredPoint add(int x, int y):
    return new ColoredPoint(this.x + x, this.y + y, this.width, this.height)

We have to write the new definition because otherwise the add method on ColoredPoint would return Point which is bad. But now this won't work in most languages because we're overriding add but we're only disambiguating on return type. Languages don't allow you to have methods that are only disambiguated on return type, because that can be ambiguous in most cases.

So what do we do?

The only solutions I see are:

  • Make them both implement some interface like IPositionable
  • Give up on immutability.

Anything else?

thedayturns
  • 9,723
  • 5
  • 33
  • 41
  • @Thilo: I tried to make it as language agnostic as possible - pretty sure it could fit under any typed OOP language (Java, C++, or the language I'm using, AS3). I did not put the language-agnostic tag though, since I know some languages don't have OOP. – thedayturns Jun 25 '12 at 03:41
  • "Languages don't allow you to have methods that are only disambiguated on return type, because that can be ambiguous in most cases.". Yes, but how is this a problem here? You want to *override* the method, right? So there will be only one `add` method in the subclass (*replacing* the inherited one). Where is the ambiguity? – Thilo Jun 25 '12 at 04:13
  • @Thilo, yes, you are correct. When I do this in AS3 (override with different return type only) it simply marks the function "Incompatible override" and fails. I assumed it was the same in other langauges, but if it's not then I guess this question is meaningless. – thedayturns Jun 25 '12 at 04:31
  • I think you'll get much better answers with a specific problem and a specific language tag. FWIW, in Java, you could not do this until Java 5 (but now you can). – Thilo Jun 25 '12 at 04:33

1 Answers1

1

If you want to enforce immutability, you cannot have subclasses. See for example java.lang.String, which is a final class for this reason: To prevent people from subclassing String to make it mutable.

Also, why would Rect extend Point in the first place? Isn't it a completely different thing? Geometry-wise, they don't even exist in the same dimension.

Finally, I cannot see the connection between the problem of methods on subclasses returning a more restrained type (and some languages not supporting this well), and immutability.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • It's not possible to *enforce* immutability on unsealed types, but it is possible for the specification of a class or interface to document that any subtype which does not meet certain conditions shall be considered broken. For example, in .net, if an object properly implements `IComparable`, then the repeatedly calling `CompareTo()`, with the same comparand passed in must always yield the same value. Routines like `Array.Sort` rely upon this behavior for correct operation. If for some particular objects `X` and `Y`, `X.CompareTo(Y)` sometimes yields +1 and sometimes -1, ... – supercat Jun 25 '12 at 18:46
  • ...and an attempt is made to call `Array.Sort()` on an array containing both those objects, the fact that objects other than `X` and `Y` might end up mis-sorted should be blamed on the broken implementation of `IComparable`, rather than on any "bug" in the sort routine. There are times when it may be useful for an abstract collection class or interface to specify that any instance of a conforming implementation must always report the same contents. This may be useful in cases where many instances will hold strongly-patterned data. For example, a subclass of ImmutableMatrix might... – supercat Jun 25 '12 at 18:50
  • ...have an `[int x,int y]` property that returns zero if x!=y, and otherwise returns element `x` of a single-dimensional array. A 100x100 matrix stored using such a class would only require about 1% as much storage as would be required if `ImmutableMatrix` were a sealed class. – supercat Jun 25 '12 at 18:51
  • With respect to Java in particular, I think you can enforce immutability while allowing subclassing using package-private constructors in the extensible classes and sealed packages. See [this answer](http://stackoverflow.com/a/31215021/20394) to a Java-specific question. – Mike Samuel Jul 04 '15 at 14:28