Troubleshooting Java code that refuses to cooperate - java

The string called "code" doesn't seem to read. Why is that and how do I fix it?
My code (the snippet that causes problems):
String code;
for(int z = 0; z<x;z= z+0) // Repeat once for every character in the input string remaining
{
for(int y=0;y<2;y++) //Repeat twice
{
c = (char)(r.nextInt(26) + 'a'); //Generate a random character (lowercase)
ca = Character.toString(c);
temp = code;
code = temp + ca; //Add a random character to the encoded string
}
My error report:
--------------------Configuration: <Default>--------------------
H:\Java\Compiler.java:66: variable code might not have been initialized
temp = code;
^
1 error
Process completed.
(I am using JCreator 5.00, Java 7.)
(Yes, the error report looks stupid, but it Stack Overflow reads it as coding.)

What value would code have if x is zero? The answer is it would have no value at all (not even null). You could just initialize it to an empty string if you like:
String code = "";

Java requires that every variable is initialized before its value is used. In this example, there is a fairly obvious case in which the variable is used before it is assigned. The Java Language Spec (JLS) doesn't allow this. (If it did, the behaviour of programs would be unpredictable, including ... potentially ... JVM crashes.)
In other cases, the compiler complains when in fact the variable in question is always initialized (or so it seems). Rather than "understanding" your code, or trying to derive a logical proof of initialization, the compiler follows a specified procedure for deciding if the variable is definitely assigned. This procedure is conservative in nature, and the answer it gives is either "it is initialized" or "it might not be initialized". Hence the wording of the compilation error message.
Here is an example in which the compiler will complain, even though it is "obvious" that the variable is initialized before use:
boolean panic;
for (int i = 0; i < 10; i += 2) {
if (i % 2 == 1 && panic) { // compilation error here
System.out.println("Panic!!");
}
}
The definite assignment rules (specified in the JLS) say that panic is NOT definitely initialized at the point indicated. It is a simple matter for a person who understands the basics of formal methods to prove that i % 2 == 1 will always be false. However, the compiler can't. (And even if it could, the code is still in error given JLS rules.)

You've created a reference, but you've never initialized it. Initialize code by changing the first line to
String code = ""
Edit: Zavior pointed out that you can pull an initialized string from the cache rather than allocate space for a new one.
But why are you assigning temp to code and then code to temp plus something else? It can be set to code = code + ca.

Related

Why isn't the ArrayIndexOutOfBoundsException a compile time error?

Can someone explain to me why ArrayIndexOutOfBoundsException is a run-time exception instead of a compile-time error?
In obvious cases when the indexes are negative or greater than the array size, I don't see why it cannot be a compile-time error.
Edited: especially when the size of the array and even the indexing is known at compile time, for example int[] a = new int[10]; a[-1]=5; This should be a compilation error.
The size of the arrays may be defined only at runtime (for instance, the simplest case, if the size of an array depends on the user input).
Therefore it would be impossible to check at compile time for such kind of exceptions, by checking the accesses of an array without actually know its bounds (size).
Because it can't be detected at compile-time all the time.
Entering a[-1] = 5; is something only novices would do (as Richard Tingle said). So it's not worth the effort to update the language standard just for that kind of error. A more interesting case would be a[SOME_CONSTANT] = 5; where SOME_CONSTANT was defined as static final int SOME_CONSTANT = -1; (or some expression involving only constants that computes to -1) in some other class. Even then, however, if the compiler flagged this as an error, it might catch cases where the programmer has put a[SOME_CONSTANT] = 5; in an if statement that has already checked for negative values of the constant. (I'm assuming here that SOME_CONSTANT is a constant whose value could change if the application's requirements change.) So while the language could, in theory, make it illegal to write an array indexing operation that can't possibly succeed, there are good reasons not to.
P.S. This is a real issue. The Ada language does do some compile-time checking for static expressions that can't succeed, but it doesn't check this case, and there has been some discussion in the last few weeks about whether it should, or whether compilers should be allowed (but not required) to reject programs with array indexing that is known to fail.
There is no way to check all indexes at compile time, because they can be variables and its values can change at runtime. If you have array[i] and i is the result of reading a file, you can evaluate i when executing the program. Even if you use a variable, remember that you can reassign your array changing its capacity. Again, this can be checked only ar runtime.
Check this question for more information: Runtime vs Compile time.
As well as agreeing with the fact that array size can't be checked at compile time, I want to add another note on the limit of the size of an array, which is expected to be in the range of primitive int:
// This compiles, because the size evaluates to an integer.
int[] array = new int[Integer.MAX_VALUE + 1];
// This doesn't compile.
int[] array = new int[Long.MAX_VALUE];
And this error is because of length field (int) of arrays which are special Java objects.
When working with pointers it's possible to have negative indexes and not have an error if you have correctly reserved the memory position you will access. Here is an example. When working with low-level programming languages things like this one are very frequently done but they don't have a lot of sense in high-level languages, at least for me.
int arr[10];
int* p = &arr[2];
int x = p[-2]; // valid: accesses arr[0]
if you try to do:
arr[-5] //you will access and invalid block of memory, this why you get the error.
this may result a very helpful and interesting:
http://www-ee.eng.hawaii.edu/~tep/EE160/Book/chap7/subsection2.1.3.2.html

Error that is neither syntactic nor semantic?

I had this question on a homework assignment (don't worry, already done):
[Using your favorite imperative language, give an example of
each of ...] An error that the compiler can neither catch nor easily generate code to
catch (this should be a violation of the language definition, not just a
program bug)
From "Programming Language Pragmatics" (3rd ed) Michael L. Scott
My answer, call main from main by passing in the same arguments (in C and Java), inspired by this. But I personally felt like that would just be a semantic error.
To me this question's asking how to producing an error that is neither syntactic nor semantic, and frankly, I can't really think of situation where it wouldn't fall in either.
Would it be code that is susceptible to exploitation, like buffer overflows (and maybe other exploitation I've never heard about)? Some sort of pit fall from the structure of the language (IDK, but lazy evaluation/weak type checking)? I'd like a simple example in Java/C++/C, but other examples are welcome.
Undefined behaviour springs to mind. A statement invoking UB is neither syntactically nor semantically incorrect, but rather the result of the code cannot be predicted and is considered erroneous.
An example of this would be (from the Wikipedia page) an attempt to modify a string-constant:
char * str = "Hello world!";
str[0] = 'h'; // undefined-behaviour here
Not all UB-statements are so easily identified though. Consider for example the possibility of signed-integer overflow in this case, if the user enters a number that is too big:
// get number from user
char input[100];
fgets(input, sizeof input, stdin);
int number = strtol(input, NULL, 10);
// print its square: possible integer-overflow if number * number > INT_MAX
printf("%i^2 = %i\n", number, number * number);
Here there may not necessarily be signed-integer overflow. And it is impossible to detect it at compile- or link-time since it involves user-input.
Statements invoking undefined behavior1 are semantically as well as syntactically correct but make programs behave erratically.
a[i++] = i; // Syntax (symbolic representation) and semantic (meaning) both are correct. But invokes UB.
Another example is using a pointer without initializing it.
Logical errors are also neither semantic nor syntactic.
1. Undefined behavior: Anything at all can happen; the Standard imposes no requirements. The program may fail to compile, or it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
Here's an example for C++. Suppose we have a function:
int incsum(int &a, int &b) {
return ++a + ++b;
}
Then the following code has undefined behavior because it modifies an object twice with no intervening sequence point:
int i = 0;
incsum(i, i);
If the call to incsum is in a different TU from the definition of the function, then it's impossible to catch the error at compile time, because neither bit of code is inherently wrong on its own. It could be detected at link time by a sufficiently intelligent linker.
You can generate as many examples as you like of this kind, where code in one TU has behavior that's conditionally undefined for certain input values passed by another TU. I went for one that's slightly obscure, you could just as easily use an invalid pointer dereference or a signed integer arithmetic overflow.
You can argue how easy it is to generate code to catch this -- I wouldn't say it's very easy, but a compiler could notice that ++a + ++b is invalid if a and b alias the same object, and add the equivalent of assert (&a != &b); at that line. So detection code can be generated by local analysis.

disable an intellij compiler error

I'm getting a "Variable TMP_1 might not have been initialized" error. Here's the snippet:
10 case 1000:
11 Double TMP_1 = len(T$);
12 I = 1d;
13 case 1001:
14 if (I.compareTo(TMP_1) > 0) {
The error is being reported on line 14. In my program it isn't possible to get to case 1001 without executing the code block at case 1000. Apparently Intellij can't figure that out. How can I disable this error? I'd rather take my changes with a null pointer exception.
The source code was generated by a compiler I wrote (the source language is an ancient BASIC.) Relocating the assignment on line 11 would be very difficult.
EDIT - See Mechanical snail's explanation below. This isn't a compiler bug at all; this is a simple program bug. The issue is that the way I have simulated BASIC's GOTO statement requires that I leave the switch statement. And when I do the tmp variable goes out of scope.
Final edit - I changed the code generator to remove the TMP variables entirely.
case 2026:
V = (asc(V$)) - (asc(" "));
dataCursor.restore();
for (J = 1d; J <= ((V * 8d) * 10d); J++) {
X = dataCursor.read();
}
Previously the arithmetic in the for loop was being done using tmp variables set before the 2026 label. Now because there aren't any, there's no problem.
The Java compiler isn't smart enough to prove that the variable you're switching on will never be 1001 until after the code that initializes the variable is executed. Remember that Java variable declarations are completely static; by design, Java only allows your variable to be used in ways that make sense, i.e. are initialized before use. And proving that this happens, for general code, is equivalent to solving the halting problem. (For all that the compiler knows, the expression I.compareTo(TMP_1) > 0 could be nonsense, since it refers to a nonexistent variable. (More precisely, the variable is declared in the scope of the switch statement's body, but the code that initializes it would not execute if you skip to the label case 1001:.))
You aren't permitted to turn this error into a warning; that's one of the drawbacks of a static language. In particular, the Java Language Specification, chapter 16 requires:
For every access of a local variable [...] x, x must be definitely assigned before the access, or a compile-time error occurs.
and the variable is not "definitely assigned" (as defined in the spec) before access. IntelliJ compiles your code using a Java compiler (usually javac). Since what you're trying to do is required to be an error by the standard, what you want is impossible (short of editing the compiler, and then it wouldn't be Java anymore).
Workaround
Instead, simply declare your variable in the surrounding scope, and initialize it to a dummy value. For example:
Double TMP_1 = null;
while(exitVar) {
switch(lblToGoTo) {
...
case 1000:
TMP_1 = len(T$);
I = 1d;
case 1001:
if (I.compareTo(TMP_1) > 0) { ... }
...
}
}

How to change the value of a variable in Java?

I am building a RPG character generator and am having a semi-difficult time with the stats of the character. The reason I am having issues is this:
int base = 10;
int iStrengthStatPoints = scan.nextInt();
int iStrength = (base +iStrengthStatPoints);
It won't compile because I am outputting the variable "iStrength" later in my code and it says cannot find symbol. I realize it is due to having iStrength being set to the value of base + iStrengthStatPoints. So I am wondering if there is a way I can assign a starting value to iStrengthStatPoints and then have the option to input a new value later on.
The thought I had was something like this:
int iStrengthStatPoints = 0;
int iStrengthStatPoints = scan.nextInt();
It would have the base value 0 but later on I could input an overriding value. Is this possible? If not is there a way to do something similar?
If you compiler is saying that it cannot find the symbol, you are trying to print iStrength out of its scope. Chances are you are declaring the variable in one method, giving it scope local to the method, and then trying to print it later in another method. This would be true even of variables declared in the class's constructor.
You only need to declare the variable (using the int keyword or other type-name) once; after that, you can assign to it (change its value) many times. So, this is fine:
int iStrengthStatPoints = 0;
and you just need to change this:
int iStrengthStatPoints = scan.nextInt();
to this:
iStrengthStatPoints = scan.nextInt();
The problem is not with the assignment statement that updates iStrength. Rather, it is with the scoping of the declaration iStrength. More precisely, the iStrength identifier is out of scope at the point you are trying to print it.
Unfortunately, neither the declaration or the problematic print code are in your code snippet, so it is not possible to say exactly what the problem is and how to fix it. Even guessing what the problem might be is futile, because there are (in general ... i.e. without seeing your code) too many possibilities.
If you want a better diagnosis, include (at least) everything from the declaration to the code that is giving the compilation error.

"If" statement, constant equality [duplicate]

This question already has answers here:
Which is more effective: if (null == variable) or if (variable == null)? [duplicate]
(9 answers)
Closed 4 years ago.
Possible Duplicate:
Order of condition checking?
When i read some source codes, the if statement is coded in this way,
if (1 == a) {
...
}
instead of
if (a == 1){
...
}
I read a programming book about the advantage of this way, but cannot remember exactly what it is about. Any one know about this ?
(Sorry if this question disturbs you :-) )
The advantage is compiler will tell you that error right away. For example, a = 1 will compile but will produce an error at run time whereas 1 = a will produce an error at compile time since 1 is not a valid lvalue.
Example: this will produce an error right away:
int a = 0;
if(1 = a) {
print("test");
}
Whereas this will compile (warnings may be produced depending on the compiler) but it will cause issues at run time.
int a = 0;
if(a = 1) {
print("test");
}
The main idea here is to make certain that you are using == in a condition instead of =.
That being said every modern compiler (ie. Eclipse) will treat the above as an error now. So it's not as big of a deal as it used to back in the notepad and vi days (in my opinion). I personally prefer the a == 1 since that seems more readable to me.
In classic C, where a condition is an integral expression, it's very easy to write
if (a = 1)
by mistake. The problem is that if you do it, the compiler won't complain, since the assignment evaluates to an integer, too. Writing the expression backward makes it such that if you make this typo, the code won't compile. It's not a bad idea to do this in C; it makes much less sense in other languages.
If you leave out an =, 1 = a is a compiler error, whereas a = 1 is a subtle mistake.

Categories