Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is type compatibility not applicable to primitives as well when overriding methods?

When we say that a Base class Base and its derived class Derived are type compatible we refer to the fact that a Base reference can refer to a Derived instance.
I.e. Base b = new Derived();
For the oposite a casting would be needed as the types are not type compatible.
Now is this concept not applicable to primitive types?
I mean this

short shortNumber = 10;  
int intNumber = shortNumber;  

seems like the same thing to me (as also no casting is needed and both short and int are integral types).
So when overiding a method in the base class, why is it acceptable that the return type be either the same or at least type compatible with the base's class return type but this is not applicable to integral types for example as well?
E.g. why is this not acceptable?

public class Person {    

    public int getId(){  
        return 1;  
    }           
}   


public class Employee extends Person {    

    public short getId(){  
        return 0;  
    }  

}  
like image 413
Cratylus Avatar asked Jul 22 '12 09:07

Cratylus


4 Answers

The direct answer, why your code example is not valid, is simple: The Java language feature of covariant return types explicitly does not apply to primitives. See JLS 8.4.5 and JLS 8.4.8.3.

Autoboxing does not apply here. If you changed your return types to Integer and Short, they would still not be return-type-substitutable, because neither is a subclass of the other.

I can not answer the question "why does the JLS not allow covariant return types for primitives", i.e. why the language designers decided it should not be allowed.

like image 138
Christian Semrau Avatar answered Nov 01 '22 06:11

Christian Semrau


Since Java 1.5, your shorts and ints are all auto-boxeable to Short and Integer, and Short does not extend Integer (e.g. it has a different MAX_VALUE).

That's one reason this would be problematic, but I think the true reasons are one of those java language design decisions: if you are going to be changing the type, we want you to be aware of it.

like image 22
Miquel Avatar answered Nov 01 '22 05:11

Miquel


you can not override method on the basis of return types, it's not allowed and compiler will complain that it'll not be treated as overridden method.

Also function calls are not deterministic on the bases of return types. For example if you call

someObj.getId();

How the compiler will determine which method should be called? does not matter from the compiler point of view that you are not handling the returned value.

like image 2
gmuhammad Avatar answered Nov 01 '22 06:11

gmuhammad


  1. JLS #8.4.8.3: Requirements in Overriding and Hiding

    If a method declaration d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be return-type-substitutable (§8.4.5) for d2, or a compile-time error occurs.
    This rule allows for covariant return types - refining the return type of a method when overriding it.

  2. JLS #8.4.5: Method Return Type - objects and primitves are not treated in the same way (emphasis mine):

    method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:

    • If R1 is void then R2 is void.
    • If R1 is a primitive type, then R2 is identical to R1.
    • If R1 is a reference type then:
      • R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or
      • R1 = |R2|

As for your initial example, it is called a widening conversion (short -> int) and does not apply in the context of method overriding.

like image 2
assylias Avatar answered Nov 01 '22 07:11

assylias