Hi again. Ending last pages from this amazing book of OCA study guide I have a question that still i couldn't solve. It's about how does compiler work.
String type = "moose";
Object obj = type;
Integer number = (Integer) obj;
Because when I see this code example about ClassCastException I think that the compiler can't realize the error in the third line because maybe it works line by line and it can't make a trace or a kind of logical trace about the code.
I mean, I would have figured that maybe the compiler could think: "As I know that the reference variable "obj" is pointing to a String object (because I realize it from the second line), in third line I'm looking that this variable is trying to be cast to an Integer type which I can't allow".
So, unlike that, compiler can't realize that and it compiles the code and then at runtime we get the ClassCastException.
I wish you can understand what's my question about and thanks a lot for your help. I hope to pass my OCA exam that i want to do in two or three weeks and it will be thanks this awesome book and your help.
There are sometimes cases like this, where we might expect the compiler to be smarter than it is. In many of these cases though, it's not that the compiler writers couldn't have made it smarter - rather, they're not allowed to make it smarter. The Java Language Specification often says exactly when a program should be allowed to compile, and when it may not. And the rules for this may be somewhat oversimplified, compared to what we could have done.
Why is this? Well, the thing is that we want Java programs to be somewhat standardized, able to compile and run on many different systems. "Write once, run anywhere" was the idea. And while this might not be 100% possible, or even 100% desirable, it's still generally the goal. And so, we don't really want programs to compile on some systems and not others. That's why compilers are required to follow particular rules here.
In this case, the rule the compiler is following is that, after a variable is declared, it remembers only the declared type of the variable. Regardless of that it's actually assigned to. So "type" is a String, and "obj" is an Object, and "number" is an Integer. Even though obj = type means that obj is really a String, at runtime, and thus the cast to (Integer) will fail... it will have to fail at runtime, not compilation.
Note that it's perfectly legal for a smarter compiler to give you a warning here. And in fact, when I put your code into IntelliJ, I see the warning: "Casting 'obj' to 'Integer' may produce ClassCastException". Good. But IntelliJ is only allowed to warn me, not to prevent the code from compiling.
Does IntelliJ still issue that warning if you change the first line to declare type as an Integer?
Compilers only check syntax rules. You're not running the program when you compile it so none of the runtime type checking that would produce a ClassCastException would occur. There's only so much a compiler can infer or deduce about your program using the language syntax rules.
Probably the best way to understand how the compiler works is to try to write one yourself, even for a simple grammar.
Junilu Lacar wrote:Does IntelliJ still issue that warning if you change the first line to declare type as an Integer?
Good question. No, in that case the warning changes to a different warning, "Cast may be removed by changing the type of 'obj' to 'Integer'". So, IntelliJ is definitely reacting to the what has been assigned to the obj variable, not just to the declared type of obj.
Junilu Lacar wrote:Compilers only check syntax rules.
Well, that's an oversimplification. There are reachability and definite assignment rules which check more than the syntax of individual statements - rather, they check whether it's possible for given statement to be reached, based on preceding statements. Or they check whether a variable has been assigned to, on each of the possible code paths to reach a given point. The latter in particular is similar to what the OP is asking about here. But, Java's creators chose to set their requirements to include only some of the things they could check for, omitting some others.
Good points about reachability and definite assignment. One thing that compiler designers factor in is performance So maybe some of the limitations we're discussing here were influenced by performance considerations as well.