I also think about such things:
Suppose we have this type:
public interface Foo { int getID(); }
Then, for some reason, the ID type is entered:
public interface Foo { FooID getID(); }
Now suppose that some client was written before the change, and the client contains the following code:
if (A.getID() == B.getID()) { someBehavior(); }
Where A and B Foos .
This code would be corrupted after the change, because comparing the primitive equality ( == ) between int s, which was normal before the change, now incorrectly compares reference values, and does not call equals(Object) for identifiers.
Had getID() from the very beginning produced Integer , the correct client code would be (normal, the correct client code could be like that. Box conversions would be applied with == to make this work too):
if (A.getID().equals(B.getID())) { someBehavior(); }
This is still true after software development.
If the change were "reverse", in other words, if getID() originally created some type of FooID , then if it were changed to create an int , the compiler would complain about calling equals(Object) on the primitive and the client code would be fixed.
There seems to be some sense of “future verification” with a non-primitive type. I agree? Do not agree?