Is it bad practice to change state inside of an if statement? - java

I wrote some code that looks similar to the following:
String SKIP_FIRST = "foo";
String SKIP_SECOND = "foo/bar";
int skipFooBarIndex(String[] list){
int index;
if (list.length >= (index = 1) && list[0].equals(SKIP_FIRST) ||
list.length >= (index = 2) &&
(list[0] + "/" + list[1]).equals(SKIP_SECOND)){
return index;
}
return 0;
}
String[] myArray = "foo/bar/apples/peaches/cherries".split("/");
print(skipFooBarIndex(myArray);
This changes state inside of the if statement by assigning index. However, my coworkers disliked this very much.
Is this a harmful practice? Is there any reason to do it?

Yes. This clearly reduces readability. What's wrong with the following code?
int skipFooBarIndex(String[] list){
if(list.length >= 1 && list[0].equals(SKIP_FIRST))
return 1;
if(list.length >= 2 && (list[0] + "/" + list[1]).equals(SKIP_SECOND))
return 2;
return 0;
}
It's much easier to understand. In general, having side effects in expressions is discouraged as you'll be relying on the order of evaluation of subexpressions.
Assuming you count it as "clever" code, it's good to always remember Brian Kernighan's quote:
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

...However, my coworkers disliked this very much...
Yes, it is. Not just because you can code it like that, you have to.
Remember that that piece of code will eventually have to be maintained by someone ( that someone may be your self in 8 months )
Changing the state inside the if, make is harder to read and understand ( mostly because it is non common )
Quoting Martin Fowler:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand

There's an excellent reason not to do it: it's makes your code really hard to understand and reason about.

The problem is that the code would generate multiple-WTFs in a code review session. Anything that makes people go "wait, what?" has got to go.
It's sadly easy enough to create bugs even in easy-to-read code. No reason to make it even easier.

Yes, side effects are hard to follow when reviewing code.
Regarding reasons to do it: No, there is no real reason to do it. I haven't yet stumbled upon an if statement that can't be rewritten without side effects without having any loss.

The only thing wrong with it is that it's unfamiliar and confusing to people who didn't write it, at least for a minute while they figure it out. I would probably write it like this to make it more readable:
if (list.length >= 1 && list[0].equals(SKIP_FIRST)) {
return 1;
}
if (list.length >= 2 && (list[0] + "/" + list[1]).equals(SKIP_SECOND)) {
return 2;
}

Borrowed from cppreference.com:
One important aspect of C++ that is related to operator precedence is the order of evaluation and the order of side effects in expressions. In some circumstances, the order in which things happen is not defined. For example, consider the following code:
float x = 1;
x = x / ++x;
The value of x is not guaranteed to be consistent across different compilers, because it is not clear whether the computer should evaluate the left or the right side of the division first. Depending on which side is evaluated first, x could take a different value.
Furthermore, while ++x evaluates to x+1, the side effect of actually storing that new value in x could happen at different times, resulting in different values for x.
The bottom line is that expressions like the one above are horribly ambiguous and should be avoided at all costs. When in doubt, break a single ambiguous expression into multiple expressions to ensure that the order of evaluation is correct.

Is this a harmful practice?
Absolutely yes. The code is hard to understand. It takes two or three reads for anyone but the author. Any code that is hard to understand and that can be rewritten in a simpler way that is easier to understand SHOULD be rewritten that way.
Your colleagues are absolutely right.
Is there any reason to do it?
The only possible reason for doing something like that is that you have extensively profiled the application and found this part of code to be a significant bottleneck. Then you have implemented the abomination above, rerun the profiler, and found that it REALLY improves the performance.

Well, I spent some time reading the above without realising what was going on. So I would definitely suggest that it's not ideal. I wouldn't really ever expect the if() statement itself to change state.

I wouldn't recommend an if condition having side-effects without a very good reason. For me, this particular example took several looks to figure out what was going on. There may be a case where it isn't so bad, although I certainly can't think of one.

Ideally, each piece of code should do one thing. Making it do more than one thing is potentially confusing, and confusing is exactly what you don't want in your code.
The code in the condition of an if statement is supposed to generate a boolean value. Tasking it with assigning a value is making it do two things, which is generally bad.
Moreover, people expect conditions to be just conditions, and they often glance over them when they're getting an impression of what the code is doing. They don't carefully parse everything until they decide they need to.
Stick that in code I'm reviewing and I'll flag it as a defect.

You can also get ternary to avoid multiple returns:
int skipFooBarIndex(String[] list) {
return (list.length > 0 && list[0].equals(SKIP_FIRST)) ? 1 :
((list.length > 1 && (list[0] + "/" + list[1]).equals(SKIP_SECOND)) ? 2 : 0);
}
Though this example is less readable.

Speaking as someone who does a lot of maintenance programming: if I came across this I would curse you, weep and then change it.
Code like this is a nightmare - it screams one of two things
I'm new here and I need help doing the right thing.
I think I am very clever because I have saved lines of code or I have fooled the compiler and made it quicker. Its not clever, its not optimal and its not funny
;)

In C it's fairly common to change state inside if statements. Generally speaking, I find that there are a few unwritten rules on where this is acceptable, for example:
You are reading into a variable and checking the result:
int a;
...
if ((a = getchar()) == 'q') { ... }
Incrementing a value and checking the result:
int *a = (int *)0xdeadbeef;
...
if (5 == *(a++)) { ... }
And when it is not acceptable:
You are assigning a constant to a variable:
int a;
...
if (a = 5) { ... } // this is almost always unintentional
Mixing and matching pre- and post-increment, and short-circuiting:
int a = 0, b;
...
if (b || a++) { ... } // BAD!
For some reason the font for sections I'm trying to mark as code is not fixed-width on SO, but in a fixed width font there are situations where assignment inside if expressions is both sensible and clear.

Related

How does Java work with variables when evaluating a statement?

Basically what I am asking is if It's possible to use the same variable in an if statement. Assigning it a new value halfway through the statement so that I don't have to initialize a new variable. I know this is probably horrible practice but I'm just curious if it can be done.
Here is the closest I feel that I have gotten so far:
if(curID + 1 != (curID = myScanner.nextInt())) {
System.out.print(j++);
break;
} else {
j++;
}
Sorry if this is a duplicate but I couldn't seem to find anything on it. More than likely because I forgot the technical terms.
Edit: Forgot to say that when I ran it I think it just used the new variable for both instances because the loop just broke. I could be wrong though.
There is no benefit to writing
if(curID++ != (curID = myScanner.nextInt())) {
versus
if(curID != (curID = myScanner.nextInt())) {
because the value stored back by ++ will be lost by the subsequent assignment. That you're thinking of doing this suggests you're fuzzy on what these things mean.
EDITED: per discussion in comments, you're also confused about the difference between prefix and postfix forms of ++. The postfix form evaluates to the value before the increment occurs.
But in any case, the whole thing is better written without the embedded assignment.
int prevId = curId;
curId = myScanner.nextInt();
if (prevId + 1 != curId) {
...
}
EDITED: added the + 1 to make the code work as discussed in the comments, as distinct from as originally written.
Your concern that you "don't have to initialize a new variable" is misplaced. Adding prevId costs almost nothing.
Writing it per my suggestion means you don't have to wonder about what Java may or may not do (though you can readily determine it from the online Java Language Specification), since it is now obvious. And that's the most important thing in programming.

Nested ifs or ands?

I'm a beginner level programmer who's just starting to work on actual projects, and I'm starting to think about things such as efficiency and if my code looks professional. I was wondering if, when trying to check multiple booleans, is it better to use nested if statements, or multiple && and || operators.
Action action = event.getAction();
Material holding = event.getItem().getType();
if((action.equals(Action.RIGHT_CLICK_AIR)||(action.equals(Action.RIGHT_CLICK_BLOCK))))
{
if((event.hasItem())&&(holding.equals(Material.COMPASS)))
{
//if the player right clicked while holding a compass
}
}
Does this look right? I tried to group the like if-statements together. Also, if there's anything else I can do to improve my formatting, please tell me! Thanks.
Welcome to the Stack Overflow community!
There is no problem with the code shared in the question. In some cases, it is better to opt for legibility so that your co-workers will be able to understand the proposed code better. But in the end, this is very subjective.
IMHO, it is easier to understand if we write all the conditions at once. So,
Action action = event.getAction();
Material holding = event.getItem().getType();
Boolean isRequiredAction = action.equals(Action.RIGHT_CLICK_AIR) || action.equals(Action.RIGHT_CLICK_BLOCK)
if (
isRequiredAction
&& event.hasItem()
&& holding.equals(Material.COMPASS)
)
{
// logic...
}
However, if you really want advice and tips on how to refactor it and best practices in a particular language, try Code Review community.
imo for a personal taste, i would put those nested conditions in a boolean variable that can explain the behavior as much as the comment you let in the block, like:
boolean isActionRightClick = action.equals(Action.RIGHT_CLICK_AIR ||action.equals(Action.RIGHT_CLICK_BLOCK);
boolean isHoldingACompass = event.hasItem() && holding.equals(Material.COMPASS);
and then
if ( isActionRightClick && isHoldingACompass ) {...}
Yes your code looks very good to me. I used to work on big projects and uses nested if statements, or multiple && and || operators which saves time. In your code efficiency can be traced at :
if((action.equals(Action.RIGHT_CLICK_AIR)||(action.equals(Action.RIGHT_CLICK_BLOCK))))
As now check only one condition in the or statement will satisfy the if condition which will save time and also shorten the code length.
You can make this code more shorter by removing unwanted parenthesis from your code. Which you must take care in future.
For more details related to efficient coding you can visit this link:
https://docs.oracle.com/cd/E80738_01/pt854pbh2/eng/pt/tpcd/task_WritingMoreEfficientCode-0749ba.html#topofpage
This is good to think about the quality/readability of your code.
Nested "if" are a good question in most of the case i think this depends of people. Some people prefer to nest it, to evaluate condition one after another. Some other prefer to not nest for not lose the track in the block.
But in most of the case be careful to not do to much if statement and try to replace it with pattern design (Easier said than done.). You can find a lot of it in java-design-patterns
I think you could make it even more shorter by using ternary operator (?:) right.
if (expression1) {
result = 1;
} else if (expression2) {
result = 2;
} else if (expression3) {
result = 3;
} else {
result = 0;
}
result = (expression1) ? 1 : (expression2) ? 2 : (expression3) ? 3 : 0;

checking a value for reset value before resetting it - performance impact?

I have a variable that gets read and updated thousands of times a second. It needs to be reset regularly. But "half" the time, the value is already the reset value. Is it a good idea to check the value first (to see if it needs resetting) before resetting (a write operaion), or I should just reset it regardless? The main goal is to optimize the code for performance.
To illustrate:
Random r = new Random();
int val = Integer.MAX_VALUE;
for (int i=0; i<100000000; i++) {
if (i % 2 == 0)
val = Integer.MAX_VALUE;
else
val = r.nextInt();
if (val != Integer.MAX_VALUE) //skip check?
val = Integer.MAX_VALUE;
}
I tried to use the above program to test the 2 scenarios (by un/commenting the 2nd "if" line), but any difference is masked by the natural variance of the run duration time.
Thanks.
Don't check it.
It's more execution steps = more cycles = more time.
As an aside, you are breaking one of the basic software golden rules: "Don't optimise early". Unless you have hard evidence that this piece if code is a performance problem, you shouldn't be looking at it. (Note that doesn't mean you code without performance in mind, you still follow normal best practice, but you don't add any special code whose only purpose is "performance related")
The check has no actual performance impact. We'd be talking about a single clock cycle or something, which is usually not relevant in a Java program (as hard-core number crunching usually isn't done in Java).
Instead, base the decision on readability. Think of the maintainer who's going to change this piece of code five years on.
In the case of your example, using my rationale, I would skip the check.
Most likely the JIT will optimise the code away because it doesn't do anything.
Rather than worrying about performance, it is usually better to worry about what it
simpler to understand
cleaner to implement
In both cases, you might remove the code as it doesn't do anything useful and it could make the code faster as well.
Even if it did make the code a little slower it would be very small compared to the cost of calling r.nextInt() which is not cheap.

Best practice for testing return value of indexOf

What do you normally write when you're testing for the return value of indexOf?
if str.indexOf("a") < 0
vs
if str.indexOf("a") == -1
Would one method be preferred over the other?
I'm actually posing this question for any function in any language that returns -1 on error.
I normally prefer the < 0 approach, because if the function is extended to return -2 on some other case, the code would still work.
However, I notice that the == -1 approach is more commonly used. Is there a reason why?
I try to implement the general principle that tests for "error conditions" should be as wide as possible. Hence I would use < 0 rather than == -1.
This is a principle I was taught during classes in formal methods during my CS degree.
On a simple if it doesn't matter too much, but on loops it's important to detect any "out of range" condition to ensure that the loop is terminated, and not to assume that the loop termination value will be hit exactly.
Take for example this:
i = 0;
while (i < 10) {
++i;
// something else increments i
}
v.s.
i = 0;
while (i != 10) {
++i;
// something else increments i
}
The latter case could fail - the former case won't.
I would also prefer the <0 approach. The reason why == -1 approach is widely used is because of the fact that the functions would indeed return -1 if the index is missing and the case of "extended function" will never happen, according to Java documentation.
In almost all cases advisable to stick to the Java doc as closely as possibly.
See Java Doc:
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#indexOf%28int%29
... according to it: -1 will be returned.
So I would always check for -1. If you have a specific value to check, its safer to check for that specific value, to protect against future code changes in java api.
For example, if you get a -2, that means that somethings is seriously wrong in your JVM. It doesn't mean "not found". It would be better for code to proceed to and cause an Exception/Error.
According to javadoc indexOf is always supposed to return -1 if character does not occur in sequence
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#indexOf%28int%29
As Sandeep Nair points out the javaDoc explains it, but I want to comment a bit.
Both would work fine and I wouldn't say one is "better" than the other. The reason many people write == -1 is that there is a general convention that search methods return -1 if "stuff cannot be found". We cannot use 0 since they are used as indices in arrays etc.
So, it's a matter of opinion. As long as the convention stays, it doesn't matter.
I'd use -1 simply because I want to check what I'm expecting.
I'm not expecting -2. If I got -2, that'd probably mean I have some issues. Checking what you're expecting is just better than checking what you may expect.

String.equals() argument ordering

I recently received a downvote for using the following in a recent answer:
String word = ...;
if ("s".equals(word) || "y".equals(word)
The downvote was given due to using a "yoda condition". I asked for further explanation but none was provided. I prefer this style to avoid a possible NullPointerException.
Is this a poor coding style? If so, why?
Bill Pugh asked this question at Devoxx 2011. The vast majority of people went for the form "xyz".equals(str). I am with Bill, now preferring str.equals("xyz").
It's fundamental to the Java tradition that we find errors as early as reasonably possible. NPEs are exceptionally common. We want to route these nulls out as soon as possible.
If you're expecting the reference to maybe null, then I don't particularly object to the backwards notation. It's nice to be explicit and easier to understand that there may be a null with a separate null check, but the reverse order should be well understood and sufficiently differentiate the code from the normal case where null is forbidden.
Working in security, some of the bugs null-tolerance accommodates are vulnerabilities.
Yoda conditions (i.e. putting a constant before a variable in a comparison) can be considered bad practice as it makes the line of code less comprehensible. In this specific case however I would state that using a Yoda condition makes the code more comprehensible as you don't have to put a extra null check in front of it.
Visit the following link to understand what is meant by Yoda Conditions|Notation
Its not a "poor coding style" its diferent way of coding.
Yoda can be usefull to track typos in some languages, i believe the -1 was not deserved to be honest but that is my personal opinion.
But Yoda can be bad as explained in this lengthy but very interesting article.
End of the day, there are supporters in favor and against this kinda of notation.
Well, it depends. If in your program "word" should never be null, word.equals("s") may actually be better. If for some obscure reason "word" will become null, you will get NullPointerException.
Think about it. If you get exception, you know something went wrong, and you can faster find mistake and fix it. If program will continue to work silently, and produce wrong results, it will be much harder to detect the problem. Actually, you may not notice there is the problem at all.
It all depends.
There are several reasons not to do it like that, however in the end it depends on you (or the team working on your product) if you think this is bad coding style. Arguments against it are:
Strings are rarely null (and you shouldn't make APIs where they are because people don't expect it)
It feels weird to put the value you are comparing to first
Code style uniformity is important, because this way is the exception, you should only do it, if everyone in your team does it.
As said I don't think these arguments are very strong, nor is the reason to do it like you. So it is mostly important to just agree on one way as your coding style and stick to that.
TL;DR; This definitely is poor coding style NOT :D
well, the yoda conditions are useful in languages where non-boolean can evaluate to a boolean value, e.g.
int test = 0;
if ( test ){ /* do something */
but this is not allowed in Java so you don't run into problems such as forgetting '=', e.g.
if ( test = 2 ){ /* do something */
instead of test == 2
the compiler will not let you do this. So the yoda condition may seem unnatural to someone who has not had to care about this (because he/she didn't use any other language but Java).
This definitely is NOT poor coding style it is just not very common to see Java code using it
yoda condition is where oup put the literal in front of the variable.
word.equals("s") is read as "word equals s"
"s".equals(word) a human reads as "s equals word"
Our brains read the first example much better and the code is clearer.
the only reason imho to use yoda conditions is to prevent assignment
as in "if (42 = i)" instead of "if(42 == i)"
You can write
if (word != null && (word.equals("s") || word.equals("y")))
instead of
if ("s".equals(word) || "y".equals(word))
In this case, first one will never cause any NullpointerException, but in my point of view in this case the 2nd one is better, though it is in Yoda Condition
There is a special case pf Yoda conditional I've not seen defended, or attacked, in any of the answers, so I'll add it for reference. This is the style of:
if(0 < x && x <= max) {
A Yoda conditional because the constant (0) is before the variable (x). The argument against Yoda conditionals is that is hinders readability. Contrast that example with the functionally equivalent
if(x <= max && x > 0) {
Do you really think that, non-Yoda variant, is more readable? I don't.
For readability when using ordering relational operators (<, <=, >, >=), I prefer the style of these heuristics:
Use consistent ordering relations: > is consistent with >=, but not with < or <=; < is consistent with <=.
Prefer < and <= to > and >=, as the default is ascending order.
Place conditions that impose a lower bound on the variable before conditions that impose an upper bound, if using < and <=. Do the opposite if using > and >=.
This very often produces a Yoda conditional for the lower bound.
One might argue that you should (unit-)test your code enough to be confident that nulls don't go where they're not supposed to. This should obviate the need for yoda conditions.

Categories

Resources