About rule (T-SCast) in FJ and downcasting in Java

 


About rule (T-SCast) in FJ and downcasting in Java

In [IPW] the authors describe the type system of Java, but extends it with the rule (T-SCast). Why?

Well. The type system of Java (essentially the type system of FJ without rule (T-SCast) ) is type-unsafe. In fact it cannot prevent us to write a program producing the following type error, as showed in [IPW]:
If we define the following classes:

class A extends Object {
    A() {super(); } 
}

class B extends Object {
    B() {super(); } 
}
then the evaluation of the following well-typed expression results in a run-time error of the sort a type system should actually prevent.
(A)(Object)new B()

Question 1: How can we guarantee a well-typed Java program not to produce this sort of type errors?

Question 2: Are there other run-time errors that be produced during the execution of well-typed Java programs?

Usually, in order to answer this sort of questions, we need to prove properties of the type system like the Subject Reduction property.

The subject reduction property cannot be proved for the type system of Java!!

In fact the expression (A)(Object)new B() is well-typed in Java, but the expression obtained after just one step of evaluation, that is (A)new B(), is not well-typed.

Any way out?

Yes. We extend the type system of FJ with rule (T-SCast). Now the Subject Reduction property holds (Theorem 2.4.1 of [IPW]). This property guarantees that, during the evaluation of a program which is well-typed in the type system of FJ, no method-not-understood error or no nonexistent-field error can ever occur (Theorem[Progress] 2.4.2 of [IPW]). Does this answer Question 2? The type system of FJ is not precisely the one of Java: it contains rule (T-SCast)...
We have to consider however that if we take a program well-typed in Java, this is also well-typed in FJ...so the Progress Theorem holds also for it. In fact, for well-typed programs in Java, rule (T-SCast) is needed only to type some expressions obtained during their evaluation.

Moreover, the subject reduction property enables us to prove Theorems 2.4.3 and 2.4.4 of [IPW] and hence to answer also Question 1. In fact, in order not to have that sort of errors in Java , it is enough to write well-typed programs without using the downcast.


Question 3: If the downcast is dangerous, why does Java use it?

Well, for instance in order to overcome some problems due to the fact that in overridden methods the type of the domain and codomain of a method cannot change. Here is an example of such a problem:

Let us assume to have a class Animal with the following binary method

public boolean compatible (Animal p) {

....

}
This method checks whether two animals can stay together

Now let us assume we have also a class Dog wich is a subclass of Animal and we wish to redefine the method compatible in order that, in case two dogs are compatible, they also bark.
The redefined method, by the Java typing rules, cannot take a Dog as argument, but an Animal. So if in the body of the redefined method we write p.bark() we get a type error detected statically, since p is considered to belong to the class Animal, where no method bark is present.

So, we are forced to use the downcast in the redefined method:

public boolean compatible (Animal p) {

.... (Dog)p.bark() ....

}

The problem now is that the type system will not prevent us to take a Dog fido and a Toucan tuky and write somewhere

 fido.compatible(tuky)
Now the method compatible will try to make tuky bark!!!

Of course we could use instanceOf, but doing this would mean that we are doing a work that should be done by the type system.

So, downcasting helps us to solve a problem, but produces onother problems....


Note: The introduction of Generics in Java should make unnecessary the use of dangerous type casts. Generics in fact make unnecessary the need of downcasts from Object. Type safety can still be broken, but programmers have now the possibility not to do that.
Note: From version 1.5 on, Java allows to have covariant return types for redefined methods.
(Thanks to Sara Capecchi)