How do you handle huge if-conditions? - language-agnostic

It's something that's bugged me in every language I've used, I have an if statement but the conditional part has so many checks that I have to split it over multiple lines, use a nested if statement or just accept that it's ugly and move on with my life.
Are there any other methods that you've found that might be of use to me and anybody else that's hit the same problem?
Example, all on one line:
if (var1 = true && var2 = true && var2 = true && var3 = true && var4 = true && var5 = true && var6 = true)
{
Example, multi-line:
if (var1 = true && var2 = true && var2 = true
&& var3 = true && var4 = true && var5 = true
&& var6 = true)
{
Example-nested:
if (var1 = true && var2 = true && var2 = true && var3 = true)
{
if (var4 = true && var5 = true && var6 = true)
{

Separate the condition in several booleans and then use a master boolean as the condition.
bool isOpaque = object.Alpha == 1.0f;
bool isDrawable = object.CanDraw && object.Layer == currentLayer;
bool isHidden = hideList.Find(object);
bool isVisible = isOpaque && isDrawable && ! isHidden;
if(isVisible)
{
// ...
}
Better yet:
public bool IsVisible {
get
{
bool isOpaque = object.Alpha == 1.0f;
bool isDrawable = object.CanDraw && object.Layer == currentLayer;
bool isHidden = hideList.Find(object);
return isOpaque && isDrawable && ! isHidden;
}
}
void Draw()
{
if(IsVisible)
{
// ...
}
}
Make sure you give your variables name that actualy indicate intention rather than function. This will greatly help the developer maintaining your code... it could be YOU!

I'm surprised no one got this one yet. There's a refactoring specifically for this type of problem:
http://www.refactoring.com/catalog/decomposeConditional.html

There are two issues to address here: readability and understandability
The "readability" solution is a style issue and as such is open to interpretation. My preference is this:
if (var1 == true && // Explanation of the check
var2 == true && // Explanation of the check
var3 == true && // Explanation of the check
var4 == true && // Explanation of the check
var5 == true && // Explanation of the check
var6 == true) // Explanation of the check
{ }
or this:
if (var1 && // Explanation of the check
var2 && // Explanation of the check
var3 && // Explanation of the check
var4 && // Explanation of the check
var5 && // Explanation of the check
var6) // Explanation of the check
{ }
That said, this kind of complex check can be quite difficult to mentally parse while scanning the code (especially if you are not the original author). Consider creating a helper method to abstract some of the complexity away:
/// <Summary>
/// Tests whether all the conditions are appropriately met
/// </Summary>
private bool AreAllConditionsMet (
bool var1,
bool var2,
bool var3,
bool var4,
bool var5,
bool var6)
{
return (
var1 && // Explanation of the check
var2 && // Explanation of the check
var3 && // Explanation of the check
var4 && // Explanation of the check
var5 && // Explanation of the check
var6); // Explanation of the check
}
private void SomeMethod()
{
// Do some stuff (including declare the required variables)
if (AreAllConditionsMet (var1, var2, var3, var4, var5, var6))
{
// Do something
}
}
Now when visually scanning the "SomeMethod" method, the actual complexity of the test logic is hidden but the semantic meaning is preserved for humans to understand at a high-level. If the developer really needs to understand the details, the AreAllConditionsMet method can be examined.
This is formally known as the "Decompose Conditional" refactoring pattern I think. Tools like Resharper or Refactor Pro! can making doing this kind of refactoring easy!
In all cases, the key to having readable and understandable code is to use realistic variable names. While I understand this is a contrived example, "var1", "var2", etc are not acceptable variable names. They should have a name which reflects the underlying nature of the data they represent.

I'll often split these up into component boolean variables:
bool orderValid = orderDate < DateTime.Now && orderStatus != Status.Canceled;
bool custValid = customerBalance == 0 && customerName != "Mike";
if (orderValid && custValid)
{
...

First, I'd remove all the == true parts, that would make it 50% shorter ;)
When I have big condition I search for the reasons. Sometimes I see I should use polymorphism, sometimes I need to add some state object. Basically, it implies a refactoring is needed (a code smell).
Sometimes I use De-Morgan's laws to simplify boolean expressions a bit.

Check out Implementation Patterns by Kent Beck. There is a particular pattern I am thinking of that may help in this situation... it is called "Guards". Rather than having tons of conditions, you can break them out into a guard, which makes it clear which are the adverse conditions in a method.
So for example, if you have a method that does something, but there are certain conditions where it shouldn't do something, rather than:
public void doSomething() {
if (condition1 && condition2 && condition3 && condition4) {
// do something
}
}
You could change it to:
public void doSomething() {
if (!condition1) {
return;
}
if (!condition2) {
return;
}
if (!condition3) {
return;
}
if (!condition4) {
return;
}
// do something
}
It's a bit more verbose, but a lot more readable, especially when you start having weird nesting, the guard can help (combined with extracting methods).
I HIGHLY recommend that book by the way.

I've seen a lot of people and editors either indenting each condition in your if statement with one tab, or matching it up with the open paren:
if (var1 == true
&& var2 == true
&& var3 == true
) {
/* do something.. */
}
I usually put the close paren on the same line as the last condition:
if (var1 == true
&& var2 == true
&& var3 == true) {
/* do something.. */
}
But I don't think this is quite as clean.

Steve Mcconell's advice, from Code Complete:
Use a multi-dimensional table. Each variable serves as an index to the table,
and the if statement turns into a table lookup. For example if (size == 3 && weight > 70)
translates into the table entry decision[size][weight_group]

Try looking at Functors and Predicates. The Apache Commons project has a great set of objects to allow you to encapsulate conditional logic into objects. Example of their use is available on O'reilly here. Excerpt of code example:
import org.apache.commons.collections.ClosureUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.functors.NOPClosure;
Map predicateMap = new HashMap();
predicateMap.put( isHonorRoll, addToHonorRoll );
predicateMap.put( isProblem, flagForAttention );
predicateMap.put( null, ClosureUtils.nopClosure() );
Closure processStudents =
ClosureUtils.switchClosure( predicateMap );
CollectionUtils.forAllDo( allStudents, processStudents );
Now the details of all those isHonorRoll predicates and the closures used to evaluate them:
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;
// Anonymous Predicate that decides if a student
// has made the honor roll.
Predicate isHonorRoll = new Predicate() {
public boolean evaluate(Object object) {
Student s = (Student) object;
return( ( s.getGrade().equals( "A" ) ) ||
( s.getGrade().equals( "B" ) &&
s.getAttendance() == PERFECT ) );
}
};
// Anonymous Predicate that decides if a student
// has a problem.
Predicate isProblem = new Predicate() {
public boolean evaluate(Object object) {
Student s = (Student) object;
return ( ( s.getGrade().equals( "D" ) ||
s.getGrade().equals( "F" ) ) ||
s.getStatus() == SUSPENDED );
}
};
// Anonymous Closure that adds a student to the
// honor roll
Closure addToHonorRoll = new Closure() {
public void execute(Object object) {
Student s = (Student) object;
// Add an award to student record
s.addAward( "honor roll", 2005 );
Database.saveStudent( s );
}
};
// Anonymous Closure flags a student for attention
Closure flagForAttention = new Closure() {
public void execute(Object object) {
Student s = (Student) object;
// Flag student for special attention
s.addNote( "talk to student", 2005 );
s.addNote( "meeting with parents", 2005 );
Database.saveStudent( s );
}
};

Well, first off, why not:
if (var1 && var2 && var2 && var3 && var4 && var5 && var6) {
...
Also, it's very hard to refactor abstract code examples. If you showed a specific example it would be easier to identify a better pattern to fit the problem.
It's no better, but what I've done in the past:
(The following method prevents short-circuiting boolean testing, all tests are run even if the first is false. Not a recommended pattern unless you know you need to always execute all the code before returning -- Thanks to ptomato for spotting my mistake!)
boolean ok = cond1;
ok &= cond2;
ok &= cond3;
ok &= cond4;
ok &= cond5;
ok &= cond6;
Which is the same as: (not the same, see above note!)
ok = (cond1 && cond2 && cond3 && cond4 && cond5 && cond6);

I resort to separate boolean values:
Bool cond1 == (var1 && var2);
Bool cond2 == (var3 && var4);
if ( cond1 && cond2 ) {}

As others have mentioned, I would analyze your conditionals to see if there's a way you can outsource it to other methods to increase readability.

In reflective languages like PHP, you can use variable-variables:
$vars = array('var1', 'var2', ... etc.);
foreach ($vars as $v)
if ($$v == true) {
// do something
break;
}

I like to break them down by level, so I'd format you example like this:
if (var1 = true
&& var2 = true
&& var2 = true
&& var3 = true
&& var4 = true
&& var5 = true
&& var6 = true){
It's handy when you have more nesting, like this (obviously the real conditions would be more interesting than "= true" for everything):
if ((var1 = true && var2 = true)
&& ((var2 = true && var3 = true)
&& (var4 = true && var5 = true))
&& (var6 = true)){

If you happen to be programming in Python, it's a cinch with the built-in all() function applied over the list of your variables (I'll just use Boolean literals here):
>>> L = [True, True, True, False, True]
>>> all(L) # True, only if all elements of L are True.
False
>>> any(L) # True, if any elements of L are True.
True
Is there any corresponding function in your language (C#? Java?). If so, that's likely the cleanest approach.

McDowell,
You are correct that when using the single '&' operator that both sides of the expression evaluate. However, when using the '&&' operator (at least in C#) then the first expression to return false is the last expression evaluated. This makes putting the evaulation before the FOR statement just as good as any other way of doing it.

#tweakt
It's no better, but what I've done in the past:
boolean ok = cond1;
ok &= cond2;
ok &= cond3;
ok &= cond4;
ok &= cond5;
ok &= cond6;
Which is the same as:
ok = (cond1 && cond2 && cond3 && cond4 && cond5 && cond6);
Actually, these two things are not the same in most languages. The second expression will typically stop being evaluated as soon as one of the conditions is false, which can be a big performance improvement if evaluating the conditions is expensive.
For readability, I personally prefer Mike Stone's proposal above. It's easy to verbosely comment and preserves all of the computational advantages of being able to early out. You can also do the same technique inline in a function if it'd confuse the organization of your code to move the conditional evaluation far away from your other function. It's a bit cheesy, but you can always do something like:
do {
if (!cond1)
break;
if (!cond2)
break;
if (!cond3)
break;
...
DoSomething();
} while (false);
the while (false) is kind of cheesy. I wish languages had a scoping operator called "once" or something that you could break out of easily.

If I was doing it in Perl, This is how I might run the checks.
{
last unless $var1;
last unless $var2;
last unless $var3;
last unless $var4;
last unless $var5;
last unless $var6;
... # Place Code Here
}
If you plan on using this over a subroutine replace every instance of last with return;

I like to break each condition into descriptive variables.
bool isVar1Valid, isVar2Valid, isVar3Valid, isVar4Valid;
isVar1Valid = ( var1 == 1 )
isVar2Valid = ( var2.Count >= 2 )
isVar3Valid = ( var3 != null )
isVar4Valid = ( var4 != null && var4.IsEmpty() == false )
if ( isVar1Valid && isVar2Valid && isVar3Valid && isVar4Valid ) {
//do code
}

if ( (condition_A)
&& (condition_B)
&& (condition_C)
&& (condition_D)
&& (condition_E)
&& (condition_F)
)
{
...
}
as opposed to
if (condition_A) {
if (condition_B) {
if (condition_C) {
if (condition_D) {
if (condition_E) {
if (condition_F) {
...
}
}
}
}
}
}
and
if ( ( (condition_A)
&& (condition_B)
)
|| ( (condition_C)
&& (condition_D)
)
|| ( (condition_E)
&& (condition_F)
)
)
{
do_this_same_thing();
}
as opposed to
if (condition_A && condition_B) {
do_this_same_thing();
}
if (condition_C && (condition_D) {
do_this_same_thing();
}
if (condition_E && condition_F) {
do_this_same_thing();
}
Most of the static analysis tools for examining code will complain if multiple conditional expressions do not use explicit parenthesis dictating expression analysis, instead of relying on operator precedence rules and fewer parenthesis.
Vertical alignment at the same indent level of open/close braces {}, open close parenthesis (), conditional expressions with parenthesis and operators on the left is an very useful practice, which greatly ENHANCES readability and clarity of the code as opposed to jamming everything that can possibly be jammed onto a single line, sans vertical alignment, spaces or parenthesis
Operator precedence rules are tricky, e.g. && has higher precedence than ||, but | has precedence than &&
So, ...
if (expr_A & expr_B || expr_C | expr_D & expr_E || expr_E && expr_F & expr_G || expr_H {
}
is a really easy multiple conditional expression for mere humans to read and evaluate improperly.
if ( ( (expr_A)
& (expr_B)
)
|| ( (expr_C)
| ( (expr_D)
& (expr_E)
)
)
|| ( (expr_E)
&& ( (expr_F)
& (expr_G)
)
)
|| (expr_H)
)
{
}
There is nothing wrong with horizontal space (linefeeds), vertical alignment, or explicit parenthesis guiding expression evaluation, all of which ENHANCES readability and clarity

If you do this:
if (var1 == true) {
if (var2 == true) {
if (var3 == true) {
...
}
}
}
Then you can also respond to cases where something isn't true. For example, if you're validating input, you could give the user a tip for how to properly format it, or whatever.

Related

Google Appscript IF Or statement not working

Good day everyone; I am running into an error I can't explain. The scenario is as follows, I have two input boxes that collect information. If no value is entered, I want the if statement to handle it and cause a break. The Input box also has an "x" to close the box, which returns a value of "Cancel". What I am trying to do is capture a condition where if no value is entered OR cancel is passed through, a break will occur. Right now, the problem is Google completely ignores the Or statement. I know individually, my IF logic works, but when coupled with OR it doesn't recognize the condition.
This is my current code:
var propnumber = Browser.inputBox('Enter RFI/RFQ Number', Browser.Buttons.OK);
if(propnumber != "" || propnumber != 'cancel'){} else{
SpreadsheetApp.getActiveSpreadsheet().toast('You must enter a value')
return
};
var myName = Browser.inputBox("Enter the Component Name",Browser.Buttons.OK_CANCEL);
if(myName != 'cancel')
{
I do something
}
As I mentioned in my description, my propnumber condition ignores the or and always accepts the value of cancel or blank. If I remove the or ( || ) then it works with one condition at a time.
I am sure this is something trivial any help appreciated.
What's wrong
The logic in the following part of your code
if(propnumber != "" || propnumber != 'cancel'){
// I assume some code will go here
} else{
SpreadsheetApp.getActiveSpreadsheet().toast('You must enter a value')
return
};
does not match the logic you've described here:
if no value is entered OR cancel is passed through, a break will occur.
Consider the case where propnumber is 'cancel':
propnumber != "" evaluates to true
propnumber != 'cancel' evaluates to false
Therefore the if(... || ...) condition in your code evaluates to true and the (currently empty) if block runs, rather than the else.
How to fix it
Option 1: A literal translation of the logic
if no value is entered OR cancel is passed through, a break will occur
would be
if(propnumber == "" || propnumber == 'cancel') {
SpreadsheetApp.getActiveSpreadsheet().toast('You must enter a value')
return
} else {
// Some action
}
Option 2: If you wish to swap the if and else clauses, you must negate the entire condition. So this will also work:
if(!(propnumber == "" || propnumber == 'cancel')) {
// Some action
} else {
SpreadsheetApp.getActiveSpreadsheet().toast('You must enter a value')
return
}
Note the added parentheses and single negation.
Option 3: use AND instead of OR in your existing code.
The expression !(A || B) is NOT logically equivalent to !A || !B. Instead, it is equivalent to !A && !B (see DeMorgan's Law). So this will also work:
if(propnumber != "" && propnumber != 'cancel') {
// Some action
} else {
SpreadsheetApp.getActiveSpreadsheet().toast('You must enter a value')
return
}

Excluding exaclty two numbers from being typed in a TextField

i want to exclude two numbers "3 and 4" from being typed in a TextField, i tried:
var theTextField:TextField = new TextField();
theTextField.type = TextFieldType.INPUT;
theTextField.border = true;
theTextField.x = 10;
theTextField.y = 10;
addChild(theTextField);
theTextField.restrict="0-9^3-4";
this successfuly excludes 3 & 4 from being typed in the textfield but it also prevent you from typing 33 or 45 for example, i only want to exclude 3 and 4. Any number with two or three digits that contains 3 or 4 should be allowed, any idea how can i do this?
So to restrict combinations 34 and 43 only?
Like Organis commented, you should validate the input via Event.CHANGE and if you already haven't let user to know about the restriction, show a warning of a somekind.
Insided the validation function you can check if the input text is "34" or "43" and then remove the second character from it to simulate the actual restriction:
theTextField.addEventListener(Event.CHANGE, validateInput);
function validateInput(e:Event):void{
if(e.target.text == "34" || e.target.text == "43"){
e.target.text = e.target.text.split("")[0];
}
}
You could also use RegExp to check the match, and .slice instead of .split inside the function:
var pattern:RegExp = /^[34|43]{2}$/;
if(pattern.test(e.target.text)){
e.target.text = e.target.text.slice(0,-1);
}
And if you're going to end up with more complex restriction patterns, with .split you can build more complex checks by checking the nth character and so on:
if(e.target.text.length == 2){
if((e.target.text.split("")[0] == "3" && e.target.text.split("")[1] == "4") ||
(e.target.text.split("")[0] == "4" && e.target.text.split("")[1] == "3")){
e.target.text = e.target.text.slice(0,-1);
}
}

How to make a For Loop of a nested IF Statement?

I am trying to make a for loop for this nested if statement in a Bejeweled clone I am practicing to code. As you can see it's pretty dumb to do it this way, because I want to loop through more matches, so I was wondering if there is a more efficient way than going through and making even more silly If statement nests about 7 times AND for each direction since the grid is 8 by 8.
The if ( i !== 0 ) bit is to prevent null errors. I think with the For statement if it were to be used it can be something like if ( i < loopvar ) instead
Thank you :3
if (i !== 0 && map[i][j].name == map[i-1][j].name) // this nest of if statements are gonna check the one to the left of the jewel we are looping through, and see if they match.
{
map[i][j].jewelsWest++;
if ( i !== 1 && map[i-1][j].name == map[i-2][j].name)
{
map[i][j].jewelsWest++;
}
}
I think recursion might me handy in this case:
map[i][j].jewelsWest = countMe(i, j, -1, 0);
map[i][j].jewelsEast = countMe(i, j, 1, 0);
map[i][j].jewelsNorth = countMe(i, j, 0, -1);
map[i][j].jewelsSouth = countMe(i, j, 0, 1);
private function countMe(x, y, xDiff, yDiff):int
{
if(map[x+xDiff] && map[x+xDiff][y+yDiff] && map[x][y].name == map[x+xDiff][y+yDiff].name)
{
return 1 + countMe(x+xDiff, y+yDiff, xDiff, yDiff);
}
else
{
return 0;
}
}

Checking for same values using if statement in actionscript?

I'm working on a match-3 style puzzle game using Flixel, and so I'm working on checking each row and column to see if there is a match at any given time. However, I have 6 different pieces (as of right now) that are active, and each piece is identified by an integer. Given that, I can check, for each and every single piece, by doing something like this:
public function matchingCheck():void
{
if (piecesArray[0][1] == 1 && piecesArray[1][1] == 1 && piecesArray[2][1] == 1) {
FlxG.log("Yay!");
}
}
However, this is rather unwieldy and would basically cause way too much repetition for my liking.
At the very least, I would like to be able to check if the values in these arrays are equal to one another, without having to specify which value it is. At the very best, I'd love to be able to check an entire row for three (or more) adjacent pieces, but I will settle for doing that part manually.
Thanks for your help!
EDIT: Nevermind, my edit didn't work. It was just checking if piecesArray[2][1] == 1, which makes me a sad panda.
EDIT 2: I've selected the correct answer below - it's not exactly what I used, but it definitely got me started. Thanks Apocalyptic0n3!
You could cut down on that code a little bit by using another function
private function checkValid( arrayOfItemsToCheck:Array, value:* ):Boolean {
for ( var i:Number = 0; i < arrayOfItemsToCheck.length; i++ ) {
if ( arrayOfItemsToCheck[i] != value ) {
return false;
}
}
return true;
}
Then you just do this in your if statement:
if ( checkValid( [ piecesArray[0][1], piecesArray[1][1], piecesArray[2][1] ], 1 ) ) {
FlxG.log("Yay!");
}
That does assume all items need to be equal to 1, though. It's still a lot of code, but it cuts out one set of "= 1 &&" for each check.
How about something like this which would tell you both if a match existed and what match it was:
public function checkForMatch():void{
var rows:int = piecesArray.length;
for(var i:int=0; i<rows; i++){
var match:int = checkRow(piecesArray[i]);
if(match > -1) {
FlxG.log("Yay you matched " + match);
}
}
}
private function ckeckRow(row:Array):int{
if(row[0] == row[1] == row[2]){
return row[0];
}
return -1;
}

What does this line of Actionscript do?

I'm looking at the as3delaunay library and most of the code is clear to me. This part is not, however (note the line that I put preceded with an arrow):
public function circles():Vector.<Circle>
{
var circles:Vector.<Circle> = new Vector.<Circle>();
for each (var site:Site in _sites)
{
var radius:Number = 0;
var nearestEdge:Edge = site.nearestEdge();
=======>> !nearestEdge.isPartOfConvexHull() && (radius = nearestEdge.sitesDistance() * 0.5);
circles.push(new Circle(site.x, site.y, radius));
}
return circles;
}
For reference, isPartOfConvexHull() is found in Edge.as and looks like this:
internal function isPartOfConvexHull():Boolean
{
return (_leftVertex == null || _rightVertex == null);
}
What does !nearestEdge.isPartOfConvexHull() do? Does that mean that the radius = nearestEdge.sitesDistance() * 0.5 only executes if false is returned from the call to isPartOfConvexHull()? Does that stop execution of any other code?
It is equivalent to:
if (!nearestEdge.isPartOfConvexHull()) {
radius = nearestEdge.sitesDistance() * 0.5;
}
In the following line:
var b:Boolean = expression1 && expression2;
expression2 will not be evaluated if expression1 is false because we already know the final result: b = false.
Now in the following line:
expression1 && expression2;
The same thing happens except the fact that we are not assigning the result to a variable.
And this is exactly what happens in the line you are asking about where !nearestEdge.isPartOfConvexHull() is the first expression and (radius = nearestEdge.sitesDistance() * 0.5) is the second expression.
To extends #sch answer with some explanations (I didn't knew if editing answer to almost double it was ok).
This is based on lazy execution of the interpreter. If (!nearestEdge.isPartOfConvexHull()) is False then there's no need to execute the second part of the AND statement to know it'll be False, then it's left unexecuted. If it's true the evaluation of the complete statement is needed (and then done) to tell wether or not this boolean is True. So this is equivalent to an if statement.
TMHO this is bad code since it's to much condensed and hard to understand.