Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to structure conditional logic? [closed]

It occurs to me that there are number of different ways to structure conditional logic. As far as I can see, as long as we set errors to end the script (or you can imagine the same examples but with a return in a function), then the following examples are equal:

Example 1

if($condition1) {
    trigger_error("The script is now terminated");
    }

if($condition2) {
    trigger_error("The script is now terminated");
    }

echo "If either condition was true, we won't see this printed";

Example 2

if(!$condition1) {
    if(!$condition2) {
        echo "If either condition was true, we won't see this printed";
        }
    else {
        trigger_error("The script is now terminated");
        }
    }
else {
    trigger_error("The script is now terminated");
    }

Example 3

if($condition1) {
    trigger_error("The script is now terminated");
    }
else {
    if($condition2) {
        trigger_error("The script is now terminated");
        }
    else {
        echo "If either condition was true, we won't see this printed";
        }
    }

Example 4 -- Adapted from Fraser's Answer

function test($condition) { 
    if($condition) {
        trigger_error("The script is now terminated");
        }   
    }

test($condition1);

test($condition2);

echo "If either condition was true, we won't see this printed";

Personally, I lean towards writing code as in Example 1. This is because I feel that by checking for conditions that end the script (or function) in this way, I can clearly define what the script executed and not executed i.e. everything before the condition has been executed and everything after the line has not. This means when I get an error on line 147, I know immediately what has happened helping me to find a bug faster. Furthermore, if I suddenly realise I need to test $condition2 before $condition1, I can make a change by a simple copy paste.

I see a lot of code written like in Example 2 but for me, this seems much more complex to debug. This is because, when the nesting gets too great, an error will get fired off at some distant line at the bottom and be separated from the condition that caused it by a huge chunk of nested code. Additionally, altering the conditional sequence can be a lot messier.

You could hybrid the two styles, such as in Example 3, but this then seems to overcomplicate matters because all of the 'else's are essentially redundant.

Am I missing something? What is the best way to structure my conditional code? Is there a better way than these examples? Are there specific situations under which one style may be superior to another?

Edit: Example 4 looks quite interesting and is not something I had considered. You could also pass in an error message as a second parameter.

Thanks!

P.S. Please keep in mind that I might need to do some arbitrary steps inbetween checking $condition1 and $condition2 so any alternatives must accommodate that. Otherwise, there are trivially better alternatives such as if($condition1 || $condition2).

like image 704
Rupert Madden-Abbott Avatar asked Dec 10 '22 14:12

Rupert Madden-Abbott


2 Answers

I am in the Example 1 camp. As a rule of thumb, the less indentation needed, the better.

// Exit early if there are errors.
if ($n < 0) {
    die "bad n: $n";
}

// Handle trivial cases without fuss.
if ($n == 0) {
    return 0;
}

/* Now the meat of the function. */
$widget->frob($n);
foreach ($widget->blaxes as $blax) {
    checkFrobbingStatus($blax);
}
// ...And another 20 lines of code.

When you use an if/else and put the success and error code in parallel sections you make it appear as if the two code blocks are equal. In reality, the edge cases and error conditions should be de-emphasized. By intentionally handling errors early and then not putting the "important" code in an else clause I feel like that makes it visually clearer where the important code is.

"Here are all the preconditions. And now here's the good stuff."

like image 100
John Kugelman Avatar answered Feb 24 '23 03:02

John Kugelman


Personally I hate nested if-else statements so #1 for me from your examples. The other option I would look at is something like the following.

function test($condition) { 
  if($condition) {
    trigger_error("The script is now terminated");
  }   
}

test($condition1);

//do stuff...

test($condition2);

//passed the tests

EDIT: The more I think about it a functional approach is by far the best way in that it negates having to write the logic that tests the conditions more than once. It also allows greater readability because it is obvious you are 'testing' the condition (as long as you give the function a meaningful name). Also, as pointed out in the question edit it would be trivial to pass other parameters to the function. i.e.

function test($c, $msg) { 
  if($c) {
    trigger_error($msg);
  }   
}

test($condition1, "condition1 error");
test($condition2, "condition2 error");
like image 25
Fraser Avatar answered Feb 24 '23 02:02

Fraser