why not compile error on "incompatible interface cast"?

G

gg9h0st

simeple code here

-----------------------------------------------------------
class IncompInterfaceTest {
void doTest() {
ClassB b = new ClassB();
InterfaceA a = (InterfaceA)b;
}
}

interface InterfaceA{}
class ClassB{}
-----------------------------------------------------------

javac issues "ClassCastException" on runtime rather than compile
error.

as i know incompatible type casting may be caught at runtime and
compiler shows the error.

but why compiler doesn't do it's job for interfaces? it's just so
clear to be compile error to me.
 
P

Patricia Shanahan

gg9h0st said:
simeple code here

-----------------------------------------------------------
class IncompInterfaceTest {
void doTest() {
ClassB b = new ClassB();
InterfaceA a = (InterfaceA)b;
}
}

interface InterfaceA{}
class ClassB{}
-----------------------------------------------------------

javac issues "ClassCastException" on runtime rather than compile
error.

as i know incompatible type casting may be caught at runtime and
compiler shows the error.

but why compiler doesn't do it's job for interfaces? it's just so
clear to be compile error to me.

In theory, the compiler could apply flow analysis in your test case to
conclude that b references the new ClassB() result at the point of the
cast.

Without flow analysis, the compiler only knows that you are casting a
ClassB reference to InterfaceA. Its value might be a pointer to a ClassC
object, where extends ClassB and implements InterfaceA

In general, given a non-final class and an interface, the compiler has
to allow for the possibility that the class has a subclass that
implements the interface.

Patricia
 
G

gg9h0st

In theory, the compiler could apply flow analysis in your test case to
conclude that b references the new ClassB() result at the point of the
cast.

Without flow analysis, the compiler only knows that you are casting a
ClassB reference to InterfaceA. Its value might be a pointer to a ClassC
object, where extends ClassB and implements InterfaceA

In general, given a non-final class and an interface, the compiler has
to allow for the possibility that the class has a subclass that
implements the interface.

Patricia

I think I saw you a year ago here too lol

by the way :S I modified this reply so many time while I'm
understanding what you told. still unclear ^^;

so it is about implementing interface is not like extending a class.
right?

I may need abit time more to think right now.

thanks patricia :)
 
G

gg9h0st

In theory, the compiler could apply flow analysis in your test case to
conclude that b references the new ClassB() result at the point of the
cast.

Without flow analysis, the compiler only knows that you are casting a
ClassB reference to InterfaceA. Its value might be a pointer to a ClassC
object, where extends ClassB and implements InterfaceA

In general, given a non-final class and an interface, the compiler has
to allow for the possibility that the class has a subclass that
implements the interface.

Patricia

Another Qeustion along this.

Doesn't "cast operator" know it's actuall object?

em... cast operator test it's operand as a refernce variable, not far
to the object in compile stage.

and extending a class should be clear to test whle implementing a
interface is not.

is that right?
 
J

Joshua Cranmer

gg9h0st said:
Doesn't "cast operator" know it's actuall object?

em... cast operator test it's operand as a refernce variable, not far
to the object in compile stage.

and extending a class should be clear to test whle implementing a
interface is not.

is that right?

I don't totally understand what you're trying to say, but I'll take a
gander.

In principle, there is sufficient information at compile time to be
determine that the cast will fail. Such analysis, though, is impractical
or even impossible in all cases. I am not certain, but I believe that if
ClassB were final, the cast would be a compiler error.

A compiler sees the statement as "cast reference of type T1 to a
reference of type T2"; it would need additional information to be stored
to be able to prove that the object cannot, in fact, be type T2. Tools
which perform such analysis do exist, and fall under the heading of
"static analysis," which retains more information about statements in
order to detect which ones could be or are problematic. FindBugs is a
classic example of such a tool for Java.
 
G

gg9h0st

gg9h0st said:
class IncompInterfaceTest {
void doTest() {
ClassB b = new ClassB();
InterfaceA a = (InterfaceA)b;
}
}
interface InterfaceA{}
class ClassB{}
javac issues "ClassCastException" on runtime rather than compile
error.
as i [sic] know incompatible type casting may be caught at runtime and
compiler shows the error.
Patricia said:
In general, given a non-final class and an interface, the compiler has
to allow for the possibility that the class has a subclass that
implements the interface.

From the JLS section 5.5:
The detailed rules for compile-time legality of a casting conversion of a
value of compile-time reference type S to a compile-time reference type T
are as follows: ...
If S is a class type: ...
* If T is an interface type:
o If S is not a final class (¡×8.1.1), then, if there exists a supertype X of
T, and a supertype Y of S, such that both X and Y are provably distinct
parameterized types, and that the erasures of X and Y are the same, a
compile-time error occurs. Otherwise, the cast is always legal at compile time
(because even if S does not implement T, a subclass of S might).

Take S as ClassB and T as InterfaceA.

ooooooooowwwww~~ I still don't get it :S
that "a subclass of S might" part.

so compiler doesn't know what variable 'b' hold? that is oviously
ClassB.

if where ClassC extends ClassB implements InterfaceA

b = new ClassC();
means b hold ClassC object in a ClassB variable.
It CAN BE ClassB, It IS NOT ClassB.
 
G

gg9h0st

There are things that are obvious to a human reader that are not obvious
to the compiler.

The case you're talking about is a degenerate case, but there are similar
situations in which analysis of the execution of the code _could_ prove
that the cast would succeed or fail, but such analysis would be _much_
more complicated than simply looking at the initialization of the variable.

For a variety of reasons, but I think mainly just to keep things
consistent (consistent, predictable compiler behavior is always a nice
thing :) ), the compiler is simply going to assume that all such casts are
valid. It's not feasible to verify them in all cases, and so rather than
provide inconsistent behavior, the compiler doesn't bother to verify them
in any case. It's up to you, the author of the code, to not perform casts
that will fail.

Basically: pretend you're a compiler. Look at _just_ the statement being
compiled. Based solely on that statement and _statically_ known things
(e.g. the types of the identifiers in the statement), can you prove that
the cast is valid or invalid?

The answer to that question is "no". And that's exactly why the compiler
can't prove it either.

Pete

yea T_T

I spend so much time to digging it.

what you explained me makes me somehow easy. need to sleep lol

I just found that doesn't make an error while casting class on an
incompatible hierarchy makes an error.
and wanted to know.
( ClassB extends ClassA, ClassD extends ClassC,
casting ClassD to ClassB issues an error.
while ClassB implements InterfaceA, ClassD implements InterfaceD,
casting ClassD to ClassB doesn't.)

I better leave it to "compiler does like this" and move to the other
studies as a newbie.

thanks :)
 
D

Daniel Pitts

gg9h0st said:
yea T_T

I spend so much time to digging it.

what you explained me makes me somehow easy. need to sleep lol

I just found that doesn't make an error while casting class on an
incompatible hierarchy makes an error.
and wanted to know.
( ClassB extends ClassA, ClassD extends ClassC,
casting ClassD to ClassB issues an error.
while ClassB implements InterfaceA, ClassD implements InterfaceD,
casting ClassD to ClassB doesn't.)

I better leave it to "compiler does like this" and move to the other
studies as a newbie.

thanks :)
The real reason is that the compiler can easily prove that two classes
are not castable to each-other, but interfaces are trickier, because any
Object might be implementing an interface.

In your example, ClassD to ClassC actually would cause compiler error,
where ClassD to InterfaceA would not. The compiler can not disprove the
existance of ClassE extends ClassD implement InterfaceA. ClassE might
not have been written yet, but it might be available at run-time, and
the cast need not know about it at compile time to succeed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top