Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Why contravariant types accepted in method parameter for Overridden methods?  RSS feed

 
Madhan Babu B
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi all

I got a doubt regarding overriding.

in case of Overriding, the contract is

1. Same or Covariant return type
2. Same method name
3. throws fewer/narrower exceptions
4. Argument list must not change -------> For beginner level

but actually, the fourth point could be wrong.

Presumption : According to the book "Fundamentals of Object Oriented Programming" by Kim B. Bruce, the parameter of an overridden method could be of Contravariant (belonging to a super class type) type and still Overriding contract holds good.

In case of return type being co-variant, we can explain that the object obeys IS-A relation and hence the contract holds good,
but i wonder how contravariant parameters logic is explained!!!

Hope i am not mislead into such a doubt with wrong presumptions, please help!!!


 
Ulrika Tingle
Ranch Hand
Posts: 92
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Madhan Babu B wrote:
Hope i am not mislead into such a doubt with wrong presumptions, please help!!!


In Java to override a method the types in the parameter list must match exactly.


Here for example the m() method in the class B does not override the m() method in class A.
 
Madhan Babu B
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

This is a page from "Fundamentalks of Object oriented languages". Anyone please explain what is said in the last paragraph of the text.

Function types
The proper definition of subtyping for function types has provoked great
controversy and confusion, so it is worth a careful look. As discussed earlier,
we write ST for the type of functions that take a parameter of type S and
return a result of type T. If (S’ T’)  (S T), then we should be able to
use an element of the first functional type in any context in which an element
of the second type would type check.

Suppose we have a function f with type ST. In order to use a function,
f’, with type S’ T’, in place of f, the function f’ must be able to accept
an argument of type S and return a value of type T. See Figure 5.2.
To masquerade successfully as a function of type ST, function f’ must
be able to be applied to an argument, s, of type S. Because the domain of
f’ is S’, it can be applied to elements of type S as long as S  S’. In that
case, using subsumption, s can be treated as an element of type S’, making
f’(s) type-correct.
On the other hand, if the output of f’ has type T’, then T’  T will
guarantee that the output of f’ can be treated as an element of type T. Summarizing,
S’  T’ S  T if S S’ and T’ T
If we assume, as before, that CheeseType  FoodType, it follows that

(Integer -> CheeseType)  (Integer -> FoodType)
but
(FoodType ->  Integer)  (CheeseType  -> Integer)
In the latter case, if f’: FoodType  Integer, then f’ can be applied to
an expression of type CheeseType, since that expression can masquerade
as being of type FoodType.
The reverse is not true, since if f: CheeseTypeInteger, it may not be
possible to apply f to an argument of type FoodType. The body of f may
apply an operation that is only defined for expressions of type CheeseType.
For example, suppose melt is a function that can be applied to elements of
type CheeseType, but not FoodType. Thenif melt is applied to the parameter
in the body of f, an execution error would arise if the actual parameter
was of type FoodType and not CheeseType.

Procedure types may be subtyped as though they were degenerate function
types that always return a default type Void.

The subtype ordering of parameter types in function subtyping is the reverse
of what might initially have been expected, while the output types of
functions are ordered in the expected way. We say that subtyping for parameter
types is contravariant (i.e., goes the opposite direction of the relation
being proved), while the subtyping for result types of functions is covariant
(i.e., goes in the same direction).

The contravariance for parameter types can be initially confusing, because
it is always permissible to replace an actual parameter by another whose
type is a subtype of the original. However the key is that in the subtyping
rule for function types, it is the function, not the actual parameter, which is
being replaced.
Let us look at one last example to illustrate why contravariance is appropriate
for type changes in the parameter position of functions and procedures.
The contravariant rule for procedures tells us that it is possible to
replace a procedure, p, of type CheeseTypeVoid by a procedure, p’, of
type FoodTypeVoid.

The procedure p can be applied to any value, cheese, of type Cheese-
Type. Because CheeseType  FoodType, the value cheese can masquerade
as an element of type FoodType. As a result, p’ can also be applied
to the value cheese. Thus p’, and indeed any procedure of type FoodType
Void, can masquerade as an element of type CheeseTypeVoid.
 
Madhan Babu B
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
@ Ulrika Tingle

does the piece of code you've mentioned above compile? If yes, it must be "Overloading" as per your statement.

But can you tell me, justify, how it is not Overriding and it is Overloading...
 
Rob Spoor
Sheriff
Posts: 21089
85
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Because that's how the Java Language Specification specifies overriding and overloading.

You are very right that you could broaden the parameters; the Liskov substitution principle certainly has no problems with this. But as I said, Java specifies differently, and those are the rules you have to go by.
 
Ulrika Tingle
Ranch Hand
Posts: 92
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Madhan Babu B wrote:@ Ulrika Tingle

does the piece of code you've mentioned above compile? If yes, it must be "Overloading" as per your statement.

But can you tell me, justify, how it is not Overriding and it is Overloading...


It compiles. I usually verify any code I post. I've checked out that there's no overriding taking place in my example. Trying out little examples is a good way to learn I can recommend. Why don't you try it sometime.

The Java language has certain rules for when overriding applies and they aren't met in my example. Java doesn't offer every feature that's theoretically possible. For every possible features there's a tradeoff between benefit and cost to consider. That's the only justification there is in many cases. A certain feature didn't make it into Java because its usefulness couldn't compensate for the complexity it would add to the language. One of the most well-known examples is multiple inheritance of implementation which Java doesn't offer.

So in this case the m() method from A will be inherited by B which will end up with two overloaded m() methods. And because the parameter types are related by inheritance, the method selection criteria will be a little more complicated.
 
Madhan Babu B
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
thank you guys!!!
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!