1

So I know that generally speaking, I should prefer an else-if over and if if. But what if the two conditions aren't related? For example, these would be considered "related" conditionals:

if (line[a] == '{'){
    openCurly = true;
}
else if (line[a] == '}'){
    closeCurly = false;
}

Notice how the two conditionals in the if-statements are related in a way such that when one is true, the other must be false. This is because line[a] can either be { or } but not both.

Here is another example:

if (line[a] == '{')
{
    openCurly = true;
}
else if ((line[a] == ';' && !openCurly) || (line[a] == '}' && openCurly))
{
    DoSomething(line);
    line = "";
}

The second condition will never evaluate to true if the first condition if true, so it makes sense to have an else-if. However, those two conditionals look vastly different.

So, should I prefer something like this?

if (line[a] == '{')
{
    openCurly = true;
}

if ((line[a] == ';' && !openCurly) || (line[a] == '}' && openCurly))
{
    DoSomething(line);
    line = "";
}
Telescope
  • 2,068
  • 1
  • 5
  • 22
Alex
  • 462
  • 1
  • 7
  • 19
  • How could `line[a]` be `;` or `}` and *simultaneously* also `{`? Use the `else if` approach. Also shouldn't the `line[a] == '}'` branch set `openCurly = false`? – tadman Jul 02 '20 at 19:15
  • 13
    Make the decision based on whether the conditions are mutually exclusive, not how the conditions look. – Rotem Jul 02 '20 at 19:17
  • I write a lot of code without else, because in the if block I break, continue, return or exit(), and there is no life after these statements! if's and else's create branches that slow CPUs by emptying the instruction buffer or slow it by doing speculative execution, so if you can compute the answer without an if, else, or ternary operator, all the better! This thinking helped create the floating point NAN, so matrix processing could go forward without conditional processing of any part of the matrix: if anyone got a divide by zero, for instance, they just returned NAN and kept computing. – David G. Pickett Jul 02 '20 at 19:26
  • 2
    Doing the unconditional work first and the conditional work later is a good way to optimize code. However, it is also good to remove exceptions first and leave a simpler universe behind with unconditional processing. Spreading the if's around just messes up the CPU more often. – David G. Pickett Jul 02 '20 at 19:27
  • Here's a good discussion of the point that I believe David is trying to make: [Why is processing a sorted array faster than processing an unsorted array?](https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array) TL;DR: Arrange the program to maximize predictability. – user4581301 Jul 02 '20 at 19:31

2 Answers2

8

You should use an else-if statement. This is because an if-else construct only checks the second statement if the first one doesn't evaluate to true.

In the example you give,

if (line[a] == '{')
{
    openCurly = true;
}
else if ((line[a] == ';' && !openCurly) || (line[a] == '}' && openCurly))
{
    DoSomething(line);
    line = "";
}

replacing the else if with an if statement would result in the second condition being checked even if the first one is true, which is completely pointless and would also lose you some time.

In the future, make decisions to use else-if statements based on whether the conditions are mutually exclusive or not.

Telescope
  • 2,068
  • 1
  • 5
  • 22
  • 1
    To add: If you really have something that is completely and only dependent on one variable, you may want to use `switch-case` , since it not only saves as much time as `if-else` does but is also more demonstrative of all the possible values. – Nikita Demodov Jul 02 '20 at 19:21
  • What if I only have 2 if statements? Should I still be using `switch`? – Alex Jul 02 '20 at 19:24
  • 1
    Use `switch` when you have a lot of cases to check with one value. A 'switch' statement is generally shorter and easier to read than `else-if` statements. I personally wouldn't use `switch` if there were only 2 cases to check. – Telescope Jul 02 '20 at 19:26
  • 1
    @Telescope yes. As a rule of thumb I'd say 4+ cases. – Nikita Demodov Jul 02 '20 at 19:28
  • "would result in the second condition being checked even if the first one is true," does not apply if the compiler optimizes - which it is allowed to do. – chux - Reinstate Monica Jul 02 '20 at 19:33
  • I would use a `switch` when the value is an enum, regardless of number of values, and add a `default` case which normally throws an exception. It is a way of making sure that if I add an enum value in the future, I know that I need to address it in the swtich. – Rotem Jul 02 '20 at 19:34
-2

You could do something like this:

#include <stdint.h>

#define COMBINATION(x, y) ((uint16_t(x) << 8) | (uint16_t(y) << 0))

...

    switch (COMBINATION(line[a], openCurly))
    {
    case COMBINATION('{', false):
        ...
        break;
    case COMBINATION(';', false):
    case COMBINATION('}', true):
        ...;
        break;
    }
}

Some may say it's a bit of an overkill, but I think that it may actually help splitting up the logical operation of your program into a set of distinct cases, thus make it easier to handle each case precisely as desired.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
goodvibration
  • 5,980
  • 4
  • 28
  • 61
  • 1
    But why are you using a macro here? Please don't suggest that. A simple function would do just fine. – cigien Jul 02 '20 at 19:48
  • @cigien: They're obviously not the same. Performance-wise, a preprocessor definition is potentially better (depending on compiler optimizations, etc). Code-size-wize, a function is potentially better (again, depending on the compiler). Debugging-wise, a function is better (easier to debug), but if you write the preprocessor definition correctly, then you shouldn't even need to debug that area of your code. If your only excuse for this comment is "that's how it is in C++" then I recommend you switch profession and go to law school or something. – goodvibration Jul 02 '20 at 19:57
  • 1
    every expert advises against macros (excluding some edge cases where you can't get around them). Performance wise no, there is no difference. Especially with modern compiler optimization amaginz algorithms. Especially with `constexpr` and the new `consteval`. They are just not worthed at all. – bolov Jul 02 '20 at 20:28
  • @goodvibration yes, a function would be equally unreadable in this case. Coming back to the macros: there are only downsides to using macros and the only potentially upside that was in discussion was the performance which is not an upside nowadays. So yes, I listen to what experts in the field have to say, but I also listen to their arguments and I see no reason to use macros. Anyway this discussion is getting off-track. I said what I had to say. From my part this ends here. – bolov Jul 02 '20 at 21:09
  • Perhaps some answers here https://stackoverflow.com/questions/14041453/why-are-preprocessor-macros-evil-and-what-are-the-alternatives will be more persuasive. Though even those answers are just expert's opinions. I'm not sure what you objection is to expert advice. – cigien Jul 02 '20 at 21:11
  • @YunfeiChen: There's nothing religious in suggesting a solution to a problem. There is a lot of religion in saying it's wrong because "every expert advises against it". Nowhere did I say that macros should always be used, etc. If I did, then yes - that would indeed be classified as "religious". However, stating "macros should never be used (because that's what the experts say)" definitely DOES classify as a "religious" statement. – goodvibration Jul 03 '20 at 07:25
  • @goodvibration "If you write it correctly then there should be no need to debug it." Well duh. That's true with everything. But programmers tend to need to debug stuff, and I'd much rather debug a function, not a method. Besides that, this very much is overkill. The amount of time it takes to read this just to find it is just a simple if-else, written by a dev who thought they were clever. What problem is this solving? – AustinWBryan Jan 13 '23 at 01:26