Why doesn't the compiler complain about this error? - java

I am writing some Java questions to help my friends in
the Java exam. I wrote a question and I assumed
that three errors would occur in the code but the compiler
only complained about two. The code is:
class MyClass
{
static MyClass()
{
System.out.println("I am The First Statement here!");
this();
}
}
I expected the following errors:
the constructor can't be static
this can't be in a static function (since the constructor isn't valid)
this here should be the first
statement.
NetBeans isn't complaining about the second error here. Why?

When compilers encounter errors, they try to avoid so-called "secondary errors" - errors resulting from other errors, by "fixing-up" earlier errors.
For example, the compiler flags an error because of the malformed constructor declaration. It can interpret this as either a constructor, that you've tried to make static, or as a regular static method that is missing a declared return type. The compiler can fix up your declaration either by ignoring the static keyword, and treating it as a regular constructor, or it can treat it as a static method and "invent" a return type to make up for a missing return type.
It sounds like NetBeans is taking the first approach - fixing up your constructor so that it is not static. When the compiler chooses to ignore the static keyword, to avoid secondary errors, the this() call is then valid, since the compiler sees that it is in a regular constructor, so the second error is not flagged. This is actually desirable behaviour - compiler writers go to great lengths to avoid secondary errors, since they cloud the "real" errors. As soon as you fix up the static constructor yourself and remove the static keyword, the this() call will then be valid (barring error #3.)
To sum up - it's the compiler trying to show you the real errors, rather than all the subsequent problems caused by those errors.
EDIT: after an error, a compiler tries to recover by skipping over input to try to get back on track (to resync the tokenizer and parser to a known state). The portion they skip may have contained errors, or have caused an error in what the compiler subsequently correctly parses. Thus, error-recovery can lead to some errors not being reported. This is not significant from a correctness perspective - as long as the compiler flags one error (the original one that lead to error-recovery being required) that's sufficient. Error handling and error reporting is primarily about usability. A compiler would be equally correct if it just printed "error" at the first error and left you to figure out where the error is - it just wouldn't be very usable.

If I try this in IntelliJ, it gives me these messages:
Compilation completed with 2 errors and 0 warnings
(3, 11) modifier static not allowed here
(6, 12) call to this must be first statement in constructor

logically you are right, there are 3 errors in the code. However the compiler compiles the code in a sequential way. Unless the previous errors are gone it won't parse any deeper.

You must have disabled the in-time compiler setting. These are the compile time error. They must be shown.
Did you try running?

Related

What type of error occurs when using an uninitialized variable?

I would think that the following Java code would cause a RuntimeError (technically speaking) because it is referencing something non-existent (much like accessing the 8th element in an array of size 5).
int i;
System.out.println(i);
However, the IDE catches it, underlining it in red. Does that make it a syntax/compiler error? Or a runtime error that the IDE is just smart enough to catch?
Actually, is it a compiler error but not technically a syntax error? I always thought of them as synonymous, but maybe syntax errors are just a type of compiler error...
I know it's just semantics, but I'm teaching a class and feel silly not knowing what type of error it technically is.
If int i; is declaring a local variable, it is a compilation error to use it before it is assigned to; see #Eran's answer for the relevant section of the JLS.
Compilation error and compile-time errors are synonyms. (Compiler error is another synonym, though sometimes people use that to refer to bugs in the compiler.)
Does that make it a syntax/compiler error?
It is a compilation error. But it is not a syntax error.
This type of compilation error is typically called a semantic error.
A syntax error means that the code doesn't conform to the language's specified syntax (as defined by the grammar). In other words, the parser can't parse it.
A semantic error is any compilation error that isn't a syntax error. Depending on the programming language, semantic errors may include such things as:
compile time type errors
symbols that cannot be resolved by the compiler
symbols that have the wrong kind for the context
unreachable code
use of uninitialized variables
and so on.
Or a runtime error that the IDE is just smart enough to catch?
It is not a runtime error.
Actually, is it a compiler error but not technically a syntax error?
Correct.
I always thought of them as synonymous, but maybe syntax errors are just a type of compiler error...
They are not synonymous. Syntax errors are just one kind of compilation error.
(Unfortunately some Javascript implementations confusingly refer to all compilation errors as "Syntax Error". But that is not relevant if you are teaching Java. Java is not Javascript.)
It's a compile-time error, as specified by the JLS:
14.4.2. Execution of Local Variable Declarations
A local variable declaration statement is an executable statement. Every time it is executed, the declarators are processed in order from left to right. If a declarator has an initialization expression, the expression is evaluated and its value is assigned to the variable.
If a declarator does not have an initialization expression, then every reference to the variable must be preceded by execution of an assignment to the variable, or a compile-time error occurs by the rules of §16.
Have you tried compiling it without the IDE?
In Java it is detected as compile time error saying: error: variable i might not have been initialized
It's simple run time error. IDE would point that out, however if u run it you'll get some error like I needs to be initialise

Why is the Java compiler giving the incoherent ".class expected" compile error?

If I have a piece of code like this:
public class ABC {
public static void main(String[] args) {
if (true)
int a = 0;
}
}
When I compile it, Java compiler produces an error
.class expected.
I know that when we don't use braces, we can use only one statement after if.
And I also know that I will not be able to use the int variable a, because as soon as the ; is encountered, the program comes out of if, and the variable a loses it's scope.
I am not surprised that this code emits an error, but why is the error message '.class' expected?
What is Java compiler trying to say?
I suspect the problem is that the only token sequence that can legitimately follow the keyword token of int in this case is . followed by class. The declaration statement you've got at the moment isn't valid because a local variable declaration on its own isn't a Statement as per JLS 14. (It's a BlockStatement.)
Note that in the tutorialspoint environment referenced in the comment, if you use a class instead of int, a different error is produced - potentially because the set of valid tokens is different in that scenario. (String.getClass(); would be valid for example, whereas int.getClass(); wouldn't.)
There is a valid question asked in a comment:
Why this .class thing? If you know any situation in which int followed by .class can compile, then please tell me.
And that's easy - you can call a method on the Class reference returned by int.class:
public class ABC
{
public static void main(String args[])
{
if(true)
int.class.getName();
}
}
That's not useful code, but it is valid code. It compiles for me without warnings or errors.
As mentioned in comments, more recent compiler versions give more useful errors - I would recommend upgrading.
As opposed to what some commenters say, this code can actually produce that error.
int a = 0;
^
According to the Java Language Specification, a variable declaration needs to be in a code block:
Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.
I assume you already knew that.
But why the .class expected error?
The reason why the exception says .class expected, is compiler specific. Other compilers will emit not a statement or illegal start of expression.
My guess is that it is related to the way the compiler evaluates the code. The only way int can be valid at that location, is when followed by .class. So as soon as the token int is detected, the compiler expects it to be followed by .class.
For example,
if (true)
int.class.getFields();
would be a valid statement.
So the compiler gives an error that is in some way logical, that is, .class expected.
Other compilers probably evaluate the whole statement as a variable declaration, rather than separate tokens like int, a, = and 0.
Specific compiler
I do not know which specific compiler tutorialspoint.com is using, but their javac version (using javac -version) is javac 1.7.0_75 on Fedora release 21 (Twenty One) (using the command cat /etc/issue.net).
PS: I don't know if you have a specific reason for using the compiler of which you posted an image, but I suggest you start using Eclipse or Netbeans.

What is the difference between run-time error and compiler error? [duplicate]

This question already has answers here:
Runtime vs. Compile time
(26 answers)
Closed 7 years ago.
In one of my prof slides on ploymorphism, I see this piece of code with a couple of comments:
discountVariable = //will produce
(DiscountSale)saleVariable;//run-time error
discountVariable = saleVariable //will produce
//compiler error
As you can see, it says in the first casting statement that it'll produce run-time error and in the other one it says it'll produce compiler error.
What makes these errors? and how they differ from each other?
A run time error will only occur when the code is actually running.
These are the most difficult - and lead to program crashes and bugs in your code which can be hard to track down.
An example might be trying to convert a string: "hello" into an integer:
string helloWorld = "hello";
int willThrowRuntimeError = Convert.ToInt32(helloWorld);
The compiler may not see this as a problem but when run an error will be thrown.
Compiler errors are due to inaccuracies in code, where the compiler throws an error to alert you to something which will not compile, and therefore cannot be run.
An example of a compiler error would be:
int = "this is not an int";
A runtime error happens during the running of the program. A compiler error happens when you try to compile the code.
If you are unable to compile your code, that is a compiler error.
If you compile and run your code, but then it fails during execution, that is runtime.
Compile time errors refers to syntax and semantics. For example, if you do operations that involves different types. Ex: adding a string with an int, or dividing a string by a real. (read the last paragraph thou!!!)
Run Time errors are those that are detected when the program execute. For example, division by zero. The compiler can not know if the operation x/a-b will leads to division by zero until the execution.
This is a very broad explanation. There are many smart compilers, and, also, is possible to do internal casting among different types that leads to operations that make sense. It it possible to pre-compile code and see some run time errors even if the code is not executed.
Refer to this link too: Runtime vs Compile time
Compile time errors are errors of syntax and semantics.
Run time errors are errors of logic primarily. Due to something the programmer has overlooked, the program crashes e.g. division by 0, accessing a variable without initializing it first etc.
Compile Time error means that the Compiler knows that discountVariable = saleVariable must be end with a semi colon as belowdiscountVariable = saleVariable;so it will throw an error when you compile the code.
Run Time error means that the error will occur at run time, because even though you are casting saleVariable into discountVariable, the cast cannot take because they differ in type.
think you've already got the general desc of what's the difference. Specifically in the code you have shown in the OP,
In second statement, compiler compares the types on LHS and RHS and finds no implicit cast possible so it gives the error.
first statement is seen by compiler as the same, but here programmer explicitly casts the type, which is as good as telling compiler that I know what I'm doing and of course the compiler trusts you and gives you no errors.
Its because the compiler doesn't know the object type of "saleVariable" until that value has actually been set when the program is running.
Your are forcing whatever is in salesVariable into the type DiscountSale this is considered unsafe and cannot be evaluated until runtime.
Compilation/Compile time/Syntax/Semantic errors: Compilation or compile time errors are error occurred due to typing mistake, if we do not follow the proper syntax and semantics of any programming language then compile time errors are thrown by the compiler. They wont let your program to execute a single line until you remove all the syntax errors or until you debug the compile time errors.
Example: Missing a semicolon in C or mistyping int as Int.
Runtime errors: Runtime errors are the errors that are generated when the program is in running state. These types of errors will cause your program to behave unexpectedly or may even kill your program. They are often referred as Exceptions.
Example: Suppose you are reading a file that doesn't exist, will result in a runtime error.
Read more about all programming errors here
If you'd use Google, you'd get this:
Compile time error is any type of error that prevent a java program compile like a syntax error, a class not found, a bad file name for the defined class, a possible loss of precision when you are mixing different java data types and so on.
A runtime error means an error which happens, while the program is running. To deal with this kind of errors java define Exceptions. Exceptions are objects represents an abnormal condition in the flow of the program. It can be either checked or unchecked.
http://wiki.answers.com/Q/Difference_between_run_time_error_and_compile_time_error_in_java
Compiler errors are due to inaccuracies in code, where the compiler throws an error to alert you to something which will not compile, and therefore cannot be run.
Ex :- MethodOverloading
class OverloadingTest {
void sum(int a, long b) {
System.out.println("a method invoked");
}
void sum(long a, int b) {
System.out.println("b method invoked");
}
public static void main(String args[]) {
OverloadingTest obj = new OverloadingTest();
obj.sum(200, 200);// now ambiguity
}
}
Run Time errors are those that are detected when the program execute. For example, division by zero. The compiler can not know if the operation x/a-b will leads to division by zero until the execution

Why does the Java compiler only report one kind of error at a time?

I've a snippet
class T{
int y;
public static void main(String... s){
int x;
System.out.println(x);
System.out.println(y);
}
}
Here there are two error, but on compilation why only one error is shown?
The error shown is:
non-static variable y cannot be referenced from a static context
System.out.println(y);
^
But what about the error
variable x might not have been initialized
System.out.println(x);
^
The Java compiler compiles your code in several passes. In each pass, certain kinds of errors are detected. In your example, javac doesn't look to see whether x may be initialised or not, until the rest of the code actually passes the previous compiler pass.
#Greg Hewgill has nailed it.
In particular, the checks for variables being initialized, exceptions being declared, unreachable code and a few other things occur in a later pass. This pass doesn't run if there were errors in earlier passes.
And there's a good reason for that. The earlier passes construct a decorated parse tree that represent the program as the compiler understands it. If there were errors earlier on, that tree will not be an accurate representation of the program as the developer understands it. (It can't be!). If the compiler then were to go on to run the later pass to produce more error messages, the chances are that a lot of those error messages would be misleading artifacts of the incorrect parse tree. This would only confuse the developer.
Anyway, that's the way that most compilers for most programming languages work. Fixing some compilation errors can cause other (previously unreported) errors to surface.
The Dragon Book ("Compilers: Principles, Techniques, and Tools" by Aho, Sethi, and Ullman) describe several methods that compiler writers can employ to try to improve error detection and reports when given input files that don't conform to the language specification.
Some of the techniques they give:
Panic mode recovery: skip all input tokens in the input stream until you have found a "synchronizing token" -- think of ;, }, or end statement and block terminators or separators, or do, while, for, function, etc. keywords that can show intended starts of new code blocks, etc. Hopefully the input from that point forward will make enough sense to parse and return useful error messages.
Phrase level recovery: guess at what a phrase might have meant: insert semicolons, change commas to semicolons, insert = assignment operators, etc., and hope the result makes enough sense to parse and return useful error messages.
Error productions: in addition to the "legitimate" productions that recognize allowed grammar operators, include "error productions" that recognize mistakes in the language that would be against the grammar, but that the compiler authors recognize as very likely mistakes. The error messages for these can be very good, but can drastically grow the size of the parser to optimize for mistakes in input (which should be the exception, not the common case).
Global correction: try to make minimal modifications to the input string to try to bring it back to a program that can be parsed. Since the corrections can be made in many different ways (inserting, changing, and deleting any number of characters), try to generate them all and discover the "least cost" change that makes the program parse well enough to continue parsing.
These options are presenting in the chapter on parsing grammars (page 161 in my edition) -- obviously, some errors are only discovered after the input file has been parsed, but is beginning to be converted into basic blocks for optimization and code generation. Any errors that occur in the earlier syntactic levels will prevent the typical compiler from starting the code optimization and generation phases, and any errors that might be detected in these phases must wait for fixed input before they can be run.
I strongly recommend finding a copy of The Dragon Book, it'll give you some sympathy and hopefully new-found respect for our friendly compiler authors.
The whole point of an error is that the compiler doesn't know how to interpret your code correctly. That's why you should always ignore errors after the first one, because the compiler's confusion may result in extra/missing errors.

Why does Java have an "unreachable statement" compiler error?

I often find when debugging a program it is convenient, (although arguably bad practice) to insert a return statement inside a block of code. I might try something like this in Java ....
class Test {
public static void main(String args[]) {
System.out.println("hello world");
return;
System.out.println("i think this line might cause a problem");
}
}
of course, this would yield the compiler error.
Test.java:7: unreachable statement
I could understand why a warning might be justified as having unused code is bad practice. But I don't understand why this needs to generate an error.
Is this just Java trying to be a Nanny, or is there a good reason to make this a compiler error?
Because unreachable code is meaningless to the compiler. Whilst making code meaningful to people is both paramount and harder than making it meaningful to a compiler, the compiler is the essential consumer of code. The designers of Java take the viewpoint that code that is not meaningful to the compiler is an error. Their stance is that if you have some unreachable code, you have made a mistake that needs to be fixed.
There is a similar question here: Unreachable code: error or warning?, in which the author says "Personally I strongly feel it should be an error: if the programmer writes a piece of code, it should always be with the intention of actually running it in some scenario." Obviously the language designers of Java agree.
Whether unreachable code should prevent compilation is a question on which there will never be consensus. But this is why the Java designers did it.
A number of people in comments point out that there are many classes of unreachable code Java doesn't prevent compiling. If I understand the consequences of Gödel correctly, no compiler can possibly catch all classes of unreachable code.
Unit tests cannot catch every single bug. We don't use this as an argument against their value. Likewise a compiler can't catch all problematic code, but it is still valuable for it to prevent compilation of bad code when it can.
The Java language designers consider unreachable code an error. So preventing it compiling when possible is reasonable.
(Before you downvote: the question is not whether or not Java should have an unreachable statement compiler error. The question is why Java has an unreachable statement compiler error. Don't downvote me just because you think Java made the wrong design decision.)
There is no definitive reason why unreachable statements must be not be allowed; other languages allow them without problems. For your specific need, this is the usual trick:
if (true) return;
It looks nonsensical, anyone who reads the code will guess that it must have been done deliberately, not a careless mistake of leaving the rest of statements unreachable.
Java has a little bit support for "conditional compilation"
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21
if (false) { x=3; }
does not result in a compile-time
error. An optimizing compiler may
realize that the statement x=3; will
never be executed and may choose to
omit the code for that statement from
the generated class file, but the
statement x=3; is not regarded as
"unreachable" in the technical sense
specified here.
The rationale for this differing
treatment is to allow programmers to
define "flag variables" such as:
static final boolean DEBUG = false;
and then write code such as:
if (DEBUG) { x=3; }
The idea is that it should be possible
to change the value of DEBUG from
false to true or from true to false
and then compile the code correctly
with no other changes to the program
text.
It is Nanny.
I feel .Net got this one right - it raises a warning for unreachable code, but not an error. It is good to be warned about it, but I see no reason to prevent compilation (especially during debugging sessions where it is nice to throw a return in to bypass some code).
I only just noticed this question, and wanted to add my $.02 to this.
In case of Java, this is not actually an option. The "unreachable code" error doesn't come from the fact that JVM developers thought to protect developers from anything, or be extra vigilant, but from the requirements of the JVM specification.
Both Java compiler, and JVM, use what is called "stack maps" - a definite information about all of the items on the stack, as allocated for the current method. The type of each and every slot of the stack must be known, so that a JVM instruction doesn't mistreat item of one type for another type. This is mostly important for preventing having a numeric value ever being used as a pointer. It's possible, using Java assembly, to try to push/store a number, but then pop/load an object reference. However, JVM will reject this code during class validation,- that is when stack maps are being created and tested for consistency.
To verify the stack maps, the VM has to walk through all the code paths that exist in a method, and make sure that no matter which code path will ever be executed, the stack data for every instruction agrees with what any previous code has pushed/stored in the stack. So, in simple case of:
Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);
at line 3, JVM will check that both branches of 'if' have only stored into a (which is just local var#0) something that is compatible with Object (since that's how code from line 3 and on will treat local var#0).
When compiler gets to an unreachable code, it doesn't quite know what state the stack might be at that point, so it can't verify its state. It can't quite compile the code anymore at that point, as it can't keep track of local variables either, so instead of leaving this ambiguity in the class file, it produces a fatal error.
Of course a simple condition like if (1<2) will fool it, but it's not really fooling - it's giving it a potential branch that can lead to the code, and at least both the compiler and the VM can determine, how the stack items can be used from there on.
P.S. I don't know what .NET does in this case, but I believe it will fail compilation as well. This normally will not be a problem for any machine code compilers (C, C++, Obj-C, etc.)
One of the goals of compilers is to rule out classes of errors. Some unreachable code is there by accident, it's nice that javac rules out that class of error at compile time.
For every rule that catches erroneous code, someone will want the compiler to accept it because they know what they're doing. That's the penalty of compiler checking, and getting the balance right is one of the tricker points of language design. Even with the strictest checking there's still an infinite number of programs that can be written, so things can't be that bad.
While I think this compiler error is a good thing, there is a way you can work around it.
Use a condition you know will be true:
public void myMethod(){
someCodeHere();
if(1 < 2) return; // compiler isn't smart enough to complain about this
moreCodeHere();
}
The compiler is not smart enough to complain about that.
It is certainly a good thing to complain the more stringent the compiler is the better, as far as it allows you to do what you need.
Usually the small price to pay is to comment the code out, the gain is that when you compile your code works. A general example is Haskell about which people screams until they realize that their test/debugging is main test only and short one. I personally in Java do almost no debugging while being ( in fact on purpose) not attentive.
If the reason for allowing if (aBooleanVariable) return; someMoreCode; is to allow flags, then the fact that if (true) return; someMoreCode; does not generate a compile time error seems like inconsistency in the policy of generating CodeNotReachable exception, since the compiler 'knows' that true is not a flag (not a variable).
Two other ways which might be interesting, but don't apply to switching off part of a method's code as well as if (true) return:
Now, instead of saying if (true) return; you might want to say assert false and add -ea OR -ea package OR -ea className to the jvm arguments. The good point is that this allows for some granularity and requires adding an extra parameter to the jvm invocation so there is no need of setting a DEBUG flag in the code, but by added argument at runtime, which is useful when the target is not the developer machine and recompiling & transferring bytecode takes time.
There is also the System.exit(0) way, but this might be an overkill, if you put it in Java in a JSP then it will terminate the server.
Apart from that Java is by-design a 'nanny' language, I would rather use something native like C/C++ for more control.

Categories

Resources