22

When overriding a method of a superclass, Java allows the return type to be covariant.

Why are contravariant parameter types in contrast not allowed when overriding methods?

dsgriffin
  • 66,495
  • 17
  • 137
  • 137
Will
  • 2,858
  • 6
  • 33
  • 50
  • 5
    possible duplicate of [Why is there no parameter contra-variance for overriding?](http://stackoverflow.com/questions/2995926/why-is-there-no-parameter-contra-variance-for-overriding) – Don Roby Sep 15 '12 at 17:47
  • Thanks. I've seen this, but had difficulties understanding the answer in C++, since I'm completely unfamiliar with C++.. Thought it might be easier to specifically ask for Java. – Will Sep 15 '12 at 17:56
  • I read the linked post and as far as I understand gain from this feature doesn't outweigh increased surprise factor. And it's not that hard to provide overloaded method for a specific implementation. I mean what other use-cases for this feature do you see? except for calling method on the class directly? – Ivan Koblik Sep 15 '12 at 18:23

1 Answers1

18

Because that's called overloading.

In particular, the return type type can be covariant because it is not considered when overloading, and it therefore still matches the superclass or interface's implementation. Parameters are considered when overloading. You very well might have an optimization with Number doSomethingWithNumber(Integer value) compared to Number doSomethingWithNumber(Number value).

pickypg
  • 22,034
  • 5
  • 72
  • 84
  • Assuming it having contravariant parameters would still be overriding, what are the issues that we would encounter? I'm looking for something like: http://stackoverflow.com/a/2996901/715236, however what would be bad about having on method in a subclass overriding multiple in a superclass? – Will Sep 15 '12 at 18:00
  • The largest problem would be the inability to provide overloads when given any base type overload somewhere in the chain. This would wreck havoc with polymorphic function calls, as the lookup would have to change from a simple equal signature, to equal or more basic signature, and what should you call if you have both, but call the more specific one? From a design perspective, if `A extends B`, and `B extends C`, but `B` provides the the `void f(Object o)` implementation from your link, then `A` has no opportunity to implement the more specific overloaded methods. This would be a nightmare. – pickypg Sep 15 '12 at 18:32
  • 1
    Most importantly, I think, it would lead to APIs that get lazily overridden, which would result in a lot of incredibly ugly, boilerplate code that internally would be used to call the appropriate method: `void f(Object o) { if (o instanceof Integer) f((Integer)o); }`. And then you have to ask how would that even work? To allow the overriding behavior, it would mean that the `Object` parameter method overrides the `Integer` parameter method, and therefore the above code would cause an infinite recursive loop (until the stack overflowed) as it would fall right back to the `Object` method. – pickypg Sep 15 '12 at 18:37
  • Unless you use the `Object` version to simply call other methods (non-overrides), or implementations in the `super` class, which would give a concrete destination to go other than the contravariant override. This means that code would be incredibly constrained, and I expect the number of bugs here would be incredibly limiting. Not to mention that you lose overloading functionality by having a catch-all bucket that can appear outside of the original API (after all, you could, today, overload those parameters in the base class to get the desired behavior using overloading and `Object`). – pickypg Sep 15 '12 at 18:38
  • 2
    @pickypg : `Because that's called overloading.` : I almost fell from my chair reading this. Thanks for this illuminating answer. +1 – paercebal Jun 06 '13 at 12:52