2

Attempting the following:

class Base {
    public Base(){
    }
}

class Derived extends Base {
}

public class Main
{
    public static void main (String[] args)
    {
        Derived derived = (Derived) new Base();
    }
}

Causes a CastClassException, but compiles successfully. The comments on this question suggest that it's impossible for the compiler to figure out what type new Base() has until runtime -- but why should that be the case? I know that in other type systems the compiler can always infer the type of any expression, and the Java compiler certainly does some type inference with e.g. lambda expressions. And it must, at some point, know what type new Base() has if it's going to emit the correct bytecode.

Is there a theoretical limitation that prevents the Java compiler from catching this before the program runs, or is it an implementation choice?

Community
  • 1
  • 1
Patrick Collins
  • 10,306
  • 5
  • 30
  • 69
  • Because it happens at runtime?? – Hot Licks Aug 29 '14 at 02:07
  • Casting things tells the compiler to ignore it's own type information and instead trust the programmer. Which is why it doesn't catch this. The compiler says, "I know this is of type base, but the programmer said it is a Derived. They know best." – Smith_61 Aug 29 '14 at 02:08

3 Answers3

6
public static void main(String[] args) throws Exception {
    Derived derived = (Derived) getObject();
}

public static Base getObject() {
    if (Math.random() > 0.5) {
        return new Base();
    } else {
        return new Derived();
    }
}

What now? How will the compiler know? The compiler is (mostly) limited to static information. The type of an object is dynamic information.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • I hadn't thought of a case like this. It still seems more sensible to me to reject ambiguous cases -- is there any good reason to write a cast that fails 50% of the time? But I see why, I guess. – Patrick Collins Aug 29 '14 at 02:13
  • @patrick Casting is not typically considered good practice. My example was meant to illustrate that there is a limit to what a compiler can know. The language designers must have decided against special case treatment. – Sotirios Delimanolis Aug 29 '14 at 02:20
3

Any rational implementation of a language that permits subclassing will have the possibility of a cast exception (or its equivalent).

The power of a subclassing scheme is that you can have methods that operate on a generic superclass without having to know the specific subclass. But sooner or later one will need to do operations specific to the subclass, and for that one must cast the reference to the subclass. If that cast is erroneous, because you mistook the actual class of the object, then a cast exception should logically occur.

You can probably hide the cast exception behind some mechanism which, say, returns a NULL if the object was not the right type, but that's simply replacing one exception with another.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
1

The result of new Base() is a Base, which in any other context could be a Derived. The compiler doesn't propagate the special knowledge that in this case it really is a Base.

Is there a theoretical limitation that prevents the Java compiler from catching this before the program runs, or is it an implementation choice?

It's an implementation choice not to make a special case of it.

user207421
  • 305,947
  • 44
  • 307
  • 483