What is the benefit of terminating if … else if constructs with an else clause?
Asked Answered
W

13

148

Our organization has a required coding rule (without any explanation) that:

if … else if constructs should be terminated with an else clause

Example 1:

if ( x < 0 )
{
   x = 0;
} /* else not needed */

Example 2:

if ( x < 0 )
{
    x = 0;
}
else if ( y < 0 )
{
    x = 3;
}
else    /* this else clause is required, even if the */
{       /* programmer expects this will never be reached */
        /* no change in value of x */
}

What edge case is this designed to handle?

What also concerns me about the reason is that Example 1 does not need an else but Example 2 does. If the reason is re-usability and extensibility, I think else should be used in both cases.

Wallachia answered 28/1, 2016 at 5:16 Comment(17)
Maybe ask your company for the reason and benefit. At first glance, it forces the programmer to think about it and add a comment "no action required". Same reasoning behind (and at least as controversial as) Java's checked exceptions.Mycosis
Do you mean either if or else if get execute. You also want to execute the else part.Orfurd
Example 2 is actually a good example for where an assert(false, "should never go here") might make senseMycosis
@Mycosis yes, I've asked and have no good answers that's why I asked in stackoverflow. Before put the question here, I've investigated the problem too but didn't find any make sense reason.Wallachia
Our organization has similar rules but not quite this granular. The purpose in our case is two-fold. First, code consistency. Second, no loose strings / readability. Requiring the else, even when un-needed, adds clarity to the code even when its not documented. Requiring an else is something I've done in the past, even when not needed, just to make sure I've accounted for all possible results in the app.Burro
You could always defeat if with if (x < 0) { x = 0; } else { if (y < 0) { x = 3; }}. Or you could just follow such rules, many of which are foolish, simply because you are required to.Childhood
Example 2: if X is 1 it will go to else, if y is 1 it will go to else. Ideally you would only test the same variable example if x < 0 then x is under 0, elseif x > 0 then x is over 0, else (otherwise) x is 0.Sacken
For example 1: even if you see only an if without an else the value of the variable as initialized is already your else statement. Example: y="over 0"; if x < 0 then y="under 0"; print y; - so if x is -1 this will print under 0, if x is 1 this will print over 0.Sacken
Because it doesn't matter how well you code, and what your requirements are, someday that else is going to be needed. In 5 or 10 years time it's going to happen, and that else (or default) will save your life.Lectureship
@Mycosis Not simply checked exceptions, but when an exception which should be unchecked is made checked.Selfconceit
@Mycosis assert(false, "should never go here") causes warning C4002 (too many macro argument) in Visual Studio 2015. I'd use &&. IMHO C++11's static_assert adds to the confusion.Recitativo
We use guard clauses here so... else is really for very very specific cases and the recommendation is that it be avoidedKerguelen
I'm sure I answered this question about 5 years ago.Gizzard
(The answer is that you don't need it if you never make a mistake. And if the code is never edited later, by a different person. Skilled programmers do this without being ordered, because they know (having learned from experience) that it's a good idea.)Gizzard
@HotLicks so could you please give your answer once more time ?Wallachia
@Mycosis I'm a bit late, but still nobody has caught the mistake: There is no indication that the else should never happen, only that it should have no side effects (which seems normal when doing < 0 checks), so that assert is going to crash the program on what is probably the most common case where values are in expected bounds.Underhanded
@Aaron good point, at least for Example One. Example Two does say "the programmer expects this never to be reached". Either way, having something there (even just the comment as per company coding style) is a good thing.Mycosis
A
161

As mentioned in another answer, this is from the MISRA-C coding guidelines. The purpose is defensive programming, a concept which is often used in mission-critical programming.

That is, every if - else if must end with an else, and every switch must end with a default.

There are two reasons for this:

  • Self-documenting code. If you write an else but leave it empty it means: "I have definitely considered the scenario when neither if nor else if are true".

    Not writing an else there means: "either I considered the scenario where neither if nor else if are true, or I completely forgot to consider it and there's potentially a fat bug right here in my code".

  • Stop runaway code. In mission-critical software, you need to write robust programs that account even for the highly unlikely. So you could see code like

    if (mybool == TRUE) 
    {
    } 
    else if (mybool == FALSE) 
    {
    }
    else
    {
      // handle error
    }
    

    This code will be completely alien to PC programmers and computer scientists, but it makes perfect sense in mission-critical software, because it catches the case where the "mybool" has gone corrupt, for whatever reason.

    Historically, you would fear corruption of the RAM memory because of EMI/noise. This is not much of an issue today. Far more likely, memory corruption occurs because of bugs elsewhere in the code: pointers to wrong locations, array-out-of-bounds bugs, stack overflow, runaway code etc.

    So most of the time, code like this comes back to slap yourself in the face when you have written bugs during the implementation stage. Meaning it could also be used as a debug technique: the program you are writing tells you when you have written bugs.


EDIT

Regarding why else is not needed after every single if:

An if-else or if-else if-else completely covers all possible values that a variable can have. But a plain if statement is not necessarily there to cover all possible values, it has a much broader usage. Most often you just wish to check a certain condition and if it is not met, then do nothing. Then it is simply not meaningful to write defensive programming to cover the else case.

Plus it would clutter up the code completely if you wrote an empty else after each and every if.

MISRA-C:2012 15.7 gives no rationale why else is not needed, it just states:

Note: a final else statement is not required for a simple if statement.

Archive answered 28/1, 2016 at 7:57 Comment(34)
Attack of the Cosmic rays! (+1)Reign
Unfortunately, if the memory really did get corrupted, it won't hit the else clause... it'll cause run-time errors when the comparison is performed.Envoy
@Envoy Umm... yes, no, maybe? That assumption is highly system-specific. It seems you are assuming code is executed from RAM? Running code from RAM is very questionable practice for any embedded system, mission-critical or not.Archive
If memory is corrupted I expect it to wreck much more than just mybool, including maybe the checking code itself. Why don't you add another block that verifies that your if/else if/else compiled to what you expect? And then one more to verify previous verifier as well?Berniecebernier
Surely if a variable is somehow "corrupt" either the comparison will fail spectacularly or it will force the result into true or false based on whatever comparison rules are used?Sextuple
Sigh. Look guys, if you have absolutely no other experience beyond desktop programming, there's no need to make know-it-all comments about something you obviously have no experience of. This always happens when defensive programming is discussed and a PC programmer stops by. I added the comment "This code will be completely alien to PC programmers" for a reason. You do not program safety-critical software to run on RAM-based desktop computers. Period. The code itself will reside in flash ROM with ECC and/or CRC checksums.Archive
Well, I guess the compiler is prohibited from any optimization, because otherwise it might come to the conclusion that mybool cannot ever be anything but TRUE or FALSE.Coltson
@Coltson Indeed (unless mybool has a non-boolean type, as was the case back before C got its own bool; then the compiler wouldn't make the assumption without additional static analysis). And on the subject of 'If you write an else but leave it empty it means: "I have definitely considered the scenario when neither if nor else if are true".': My first reaction is to assume the programmer forgot to put code in the else block, otherwise why have an empty else block just sitting there? An // unused comment would be appropriate, not just an empty block.Etch
@Coltson That was actually the reason why I used "mybool" and TRUE/FALSE in the example, rather than bool, true and false. Assuming "mybool" is some old, home-brewn boolean type based on enums or similar.Archive
@Etch Yes, the else block needs to contain some sort of comment if there is no code. Common practice for empty else is a single semicolon plus a comment: else { ; // doesn't matter }. As there is no reason why anyone would otherwise just type an indented, single semi colon on a line of its own. Similar practice is sometimes used in empty loops: while(something) { ; // do nothing }. (code with line breaks, obviously. SO comments don't allow them)Archive
@Archive you have great an answer but like I mentioned in question, why in Example 1 not need else. Because as you answered (which focus on Example 2), else is for corruption case and the code in Example 1 can corrupt like Sample 2 or any other codes in Embedded system ,right ?Wallachia
@TrieuTheVan I tried to answer that question with an edit.Archive
I'd like to note, that this sample code with two IFs and else can go to else even in usual desktop software in multi-threaded environments, so value of mybool could be changed just in betweenBoatswain
@Archive thanks, I'm investigating more about this. About the case of corruption, could you give me a existed article or science information that have example about that (the case 'my bool' differ to both 'true' and 'false' )?Wallachia
@Archive or should I make a question for your example code, maybe people could show many cases that the else case could be coveredWallachia
@Archive after spend time investigating I think that you answer is great and I accept it. But like I said in above comment, I glad to have articles that have example about the corruption case.Wallachia
I would strongly argue that you do need the final else. Without it, it's easy for someone to come along later, monkey with the structure of several nested if statements, and cause the else statements to become improperly associated.Gizzard
@JAB: to be a little more precise, what is more important is that C has its own _Bool, which is a type with specified behaviour, e.g. values assigned to it are forced to 0 or 1, while bool is a macro in <stdbool.h> which the programme is free to undefine or redefine.Family
Is there a reason not to put an assert( false ) in the empty else-block (if appropriate)? That would document the expectation of it never happening, and help catch errors while debugging.Aikens
@RaoulSteffen In safety-critical software, you allow no debug code at all to remain in the production build. So things like assert will just be problematic. It is better to implement the error handler for the actual product and then use that one. Besides, assert doesn't really make sense in embedded systems since there is usually nothing like "standard error streams" available.Archive
I would expect assertfail() to set the reset pin in an embedded environment.Cayes
@Archive wrote "no reason anyone would type a single indented semi colon on a line by itself" I used to do that long ago. "Just a semi-colon? Obviously it means you want nothing to happen there." Now, I'll try to pull something out of the branch's parenthesis and into the body. If there is nothing to pull out for some reason, then I would now leave a comment ("; // do nothing"). But that does not change what I did once upon a time; so yes, I did have a reason, and I probably (unfortunately) left too many instances of lonely ';' in legacy code.Underhanded
@Archive As for debug code in safety-critical production code: is that actually part of the suggestion in the quoted guidelines as well or is that just the opinion of the teams you worked with? I have worked with safety-critical systems before, and think we had debug code left. Maybe not in the actual safety-critical section, but in other sections of the same program - is there a distinction for that in the guidelines?Underhanded
@Archive While I understand you are just quoting guidelines and you probably are not responsible for them, still: I have always found it silly to use memory corruption as a reason for any production code (short of things like memory testing software, obviously). My reason for dismissing such checks as unnecessary is that you are only checking a small subset of the memory and only for a small subset of time. Even if you do have a memory corruption, adding in the example code probably won't help. It is a mostly-false sense of security.Underhanded
@Aaron "No debug code" basically means no left-overs from internal testing. That's banned by multiple standards, not only MISRA-C. If you implement a full-blown error handler system, that's of course fine, as it is then part of the application and not something that potentially ended up in the source by accident. Also, there is no such thing as "safety-critical section" of a firmware, if all is executed by the same MCU. A bug in one part of the program could cause another part to go haywire. Meaning that the whole program is either safety-critical or it is not, period.Archive
@Aaron Or for memory testing, as the answer mentions: "Far more likely, memory corruption occurs because of bugs elsewhere in the code: pointers to wrong locations, array-out-of-bounds bugs, stack overflow, runaway code etc." And then of course on these systems, the actual code is always executed from flash and not RAM. A PC programmer would not understand the distinction, since they always load the program itself in RAM, and therefore they go "but if the RAM is corrupt, your program can execute any nonsense op code" which isn't true on a MCU executing code from NVM flash.Archive
@Archive I appreciate the distinction of where the code is being executed from, but that still does not dismiss the concern that if there is memory corruption, for whatever reason (bugs, heavy EM interference, the butterfly effect, a local but microscopic black hole passing through... whatever), the example if/else if/else check is still not likely to catch it, even if it is only variable data in RAM. There are many other variables in RAM, many of which you cannot so easily check for corruption (ints, pointers, floats, etc.) without redundant memory (which makes such checks pointless anyway).Underhanded
Or, for an analogy, checking that variable because it might be corrupt, when there are so many other variables that could be corrupt without being detected, is like installing a camera to watch your windows facing the baseball park to see if the window is broken but only installing 1 such camera and positioning it to observe only 1 window out of the 40 windows facing the park and equally at risk. If you are truly concerned about memory corruption enough to check for it, have a redundant variable to check against, as that would be far more likely to catch most forms of corruption.Underhanded
@Aaron This goes back to the days where RAM - including MCU peripheral memory mapped registers - were not reliable at all. They would then have to be continuously refreshed from NVM. The practice lives on and it is still good practice in a way, since NVM is most often more reliable than RAM. But mostly it is there to detect bugs and runaway code. If you ever implement proper defensive programming with a proper error handler, you'll notice how nice it is. Because the most notable effect is that your own program starts to report your own bugs back to you, often early on in the design stage.Archive
Let us continue this discussion in chat.Underhanded
@Archive please tell me how you're able to presume "you are assuming code is executed from RAM" by just reading "it'll cause run-time errors when the comparison is performed" said by Nelson. These two sentences seem irrelevant to meTheomancy
@AndyLin "It seems you are assuming code is executed from RAM?" is a question, supposedly because the other person was potentially assuming that the program itself got corrupted.Archive
@Archive Does program in somewhere other than RAM get corrupted? It seems you consider program got corrupted only happens in RAM.Theomancy
@AndyLin Yes it can be corrupted in flash, but then for different reasons than bugs or EMI. Instead it would get corrupted by flash erase/write cycle wear and data retention. Safety MCUs deal with this through hardware support by something called ECC, other MCUs by CRC32. Sometimes data in flash is also stored in 2 identical "mirror" segments. Hence the comment "The code itself will reside in flash ROM with ECC and/or CRC checksums".Archive
I
63

Your company followed MISRA coding guidance. There are a few versions of these guidelines that contain this rule, but from MISRA-C:2004:

Rule 14.10 (required): All if … else if constructs shall be terminated with an else clause.

This rule applies whenever an if statement is followed by one or more else if statements; the final else if shall be followed by an else statement. In the case of a simple if statement then the else statement need not be included. The requirement for a final else statement is defensive programming. The else statement shall either take appropriate action or contain a suitable comment as to why no action is taken. This is consistent with the requirement to have a final default clause in a switch statement. For example this code is a simple if statement:

if ( x < 0 )
{
 log_error(3);
 x = 0;
} /* else not needed */

whereas the following code demonstrates an if, else if construct

if ( x < 0 )
{
 log_error(3);
 x = 0;
}
else if ( y < 0 )
{
 x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
 /* no change in value of x */
}

In MISRA-C:2012, which supersedes the 2004 version and is the current recommendation for new projects, the same rule exists but is numbered 15.7.

Example 1: in a single if statement programmer may need to check n number of conditions and performs single operation.

if(condition_1 || condition_2 || ... condition_n)
{
   //operation_1
}

In a regular usage performing a operation is not needed all the time when if is used.

Example 2: Here programmer checks n number of conditions and performing multiple operations. In regular usage if..else if is like switch you may need to perform a operation like default. So usage else is needed as per misra standard

if(condition_1 || condition_2 || ... condition_n)
{
   //operation_1
}
else if(condition_1 || condition_2 || ... condition_n)
{
  //operation_2
}
....
else
{
   //default cause
}

Current and past versions of these publications are available for purchase via the MISRA webstore (via).

Ingrained answered 28/1, 2016 at 5:24 Comment(17)
Thank, your answer is all the content of Misra rule, but I expect a answer for my confuse in edit part of the question.Wallachia
@TrieuTheVan i have updated my answer hope it will satisfy the needIngrained
Good answer. Out of curiosity, do those guides say anything about what to do if you expect the else clause to be unreachable? (Leave off the final condition instead, throw an error, perhaps?)Thacker
I'm going to down vote for plagiarism and links that violate copyright. I'll edit the post so that it becomes clearer what's your words and what's MISRA's words. Initially this answer was nothing but a raw copy/paste.Archive
@Archive I accept it was copy/paste of the misra's coding guidance. Check the edits of the question and edits of my answer it will make u to understand better. Initially question was blank then it is edited. As per the question i am editing my answe. Any how thanks for ur editIngrained
@TrieuTheVan: Questions must not be moving targets. Make sure your question is complete before you post it.Claypan
@T.J.Crowder I didn't moving target, I just didn't mention enough and clearly my confusion. Thank for reminding.Wallachia
So using if(…) { … } else if(…) { … } else { /* meaningless comment */ } is better than using if(…) { … } else if(…) { … } /* meaningless comment */ ?Orose
@Thacker Nope, but the point of MISRA isn't to give you tight code, it's to give you safe code. Any compiler these days will optimise out unreachable code anyway, so there's no downside.Kandacekandahar
I have added a link to the document description on the MISRA site as well as a footnote describing where to obtain the document, which is available for purchase. I do not have a copy of the document myself and so cannot add page or further section numbers, I assume the included rule number will suffice. cc @ArchiveMaldon
@JasonC Well, you can't buy MISRA-C:2004 any longer, it is withdrawn in favour of MISRA-C:2012. The identical rule exists in 2012 too, but there it is rule number 15.7. We can't actually know if the OP's company implements 2004 or 2012, but the citation is taken from 2004.Archive
@Archive I think you can purchase it. It's listed for £10 (PDF) or £40 (hard copy) on the shop page (about 1/3 the way down) and I just added qty 1 to my basket. I didn't go any further than that, though. It is marked as "for reference only" with a note that it is superseded by :2012. Good point about not knowing which version the company uses; I'll edit the answer again in a moment, save some readers from being misled.Maldon
@JasonC Aha, even the 1998 version is still available. Regardless, the 2012 version is strongly recommended, as it fixed lots of issues and also supports C99.Archive
I have made the edit mentioned in my previous comment, as best as I could.Maldon
@Kandacekandahar But the issue I was asking about is about safe code. Do they say that it's safer to throw an error in an else block you expect to be unreachable, or do they say it's safer to leave off the final conditional check?Thacker
@Thacker Most of MISRA-C isn't about throwing errors, it's about making the code readable and maintainable. The point of the final "else" isn't to throw an error if it gets somewhere it shouldn't (although you can do that), it's to explicitly tell your reviewers/maintainers/coworkers that you thought about this condition and you didn't just forget about it. So comments saying "Should never get here" aren't very useful - those comments should say "Should never get here because...".Kandacekandahar
@Thacker Also as far as throwing errors goes, it depends on the reason why you shouldn't get there. If you shouldn't get there because it's genuinely unreachable based on compile-time conditions above, then a comment is fine. If you shouldn't get there because that value is valid but shouldn't happen (e.g. null pointer checks), then bailing out is definitely in order, because you can't expect the system to continue sanely when it's got to some unexpected state. What actions you take will depend on the system - fly-by-wire has different failsafe requirements from Windows. :)Kandacekandahar
L
21

This is the equivalent of requiring a default case in every switch.

This extra else will Decrease code coverage of your program.


In my experience with porting linux kernel , or android code to different platform many time we do something wrong and in logcat we see some error like

if ( x < 0 )
{
    x = 0;
}
else if ( y < 0 )
{
    x = 3;
}
else    /* this else clause is required, even if the */
{       /* programmer expects this will never be reached */
        /* no change in value of x */
        printk(" \n [function or module name]: this should never happen \n");

        /* It is always good to mention function/module name with the 
           logs. If you end up with "this should never happen" message
           and the same message is used in many places in the software
           it will be hard to track/debug.
        */
}
Lakshmi answered 28/1, 2016 at 5:29 Comment(1)
This is where __FILE__ and __LINE__ macros are a useful for making the source location easy to find if the message is ever printed.Myriad
G
9

Only a brief explanation, since I did this all about 5 years ago.

There is (with most languages) no syntactic requirement to include "null" else statement (and unnecessary {..}), and in "simple little programs" there is no need. But real programmers don't write "simple little programs", and, just as importantly, they don't write programs that will be used once and then discarded.

When one write an if/else:

if(something)
  doSomething;
else
  doSomethingElse;

it all seems simple and one hardly sees even the point of adding {..}.

But some day, a few months from now, some other programmer (you would never make such a mistake!) will need to "enhance" the program and will add a statement.

if(something)
  doSomething;
else
  doSomethingIForgot;
  doSomethingElse;

Suddenly doSomethingElse kinda forgets that it's supposed to be in the else leg.

So you're a good little programmer and you always use {..}. But you write:

if(something) {
  if(anotherThing) {
    doSomething;
  }
}

All's well and good until that new kid makes a midnight modification:

if(something) {
  if(!notMyThing) {
  if(anotherThing) {
    doSomething;
  }
  else {
    dontDoAnything;  // Because it's not my thing.
  }}
}

Yes, it's improperly formatted, but so is half the code in the project, and the "auto formatter" gets bollixed up by all the #ifdef statements. And, of course, the real code is far more complicated than this toy example.

Unfortunately (or not), I've been out of this sort of thing for a few years now, so I don't have a fresh "real" example in mind -- the above is (obviously) contrived and a bit hokey.

Gizzard answered 29/1, 2016 at 20:7 Comment(0)
T
7

This, is done to make the code more readable, for later references and to make it clear, to a later reviewer, that the remaining cases handled by the last else, are do nothing cases, so that they are not overlooked somehow at first sight.

This is a good programming practice, which makes code reusable and extend-able.

Tagmemics answered 28/1, 2016 at 5:26 Comment(0)
T
7

I would like to add to – and partly contradict – the previous answers. While it is certainly common to use if-else if in a switch-like manner that should cover the full range of thinkable values for an expression, it is by no means guaranteed that any range of possible conditions is fully covered. The same can be said about the switch construct itself, hence the requirement to use a default clause, which catches all remaining values and can, if not otherwise required anyway, be used as an assertion safeguard.

The question itself features a good counter-example: The second condition does not relate to x at all (which is the reason why I often prefer the more flexible if-based variant over the switch-based variant). From the example it is obvious that if condition A is met, x should be set to a certain value. Should A not be met, then condition B is tested. If it is met, then x should receive another value. If neither A nor B are met, then x should remain unchanged.

Here we can see that an empty else branch should be used to comment on the programmer's intention for the reader.

On the other hand, I cannot see why there must be an else clause especially for the latest and innermost if statement. In C, there is no such thing as an 'else if'. There is only if and else. Instead, the construct should formally be indented this way (and I should have put the opening curly braces on their own lines, but I don't like that):

if (A) {
    // do something
}
else {
    if (B) {
        // do something else (no pun intended)
    }
    else {
        // don't do anything here
    }
}

Should any standard happen to require curly braces around every branch, then it would contradict itself if it mentioned "if ... else if constructs" at the same time.

Anyone can imagine the ugliness of deeply nested if else trees, see here on a side note. Now imagine that this construct can be arbitrarily extended anywhere. Then asking for an else clause in the end, but not anywhere else, becomes absurd.

if (A) {
    if (B) {
        // do something
    }
    // you could to something here
}
else {
    // or here
    if (B) { // or C?
        // do something else (no pun intended)
    }
    else {
        // don't do anything here, if you don't want to
    }
    // what if I wanted to do something here? I need brackets for that.
}

In the end, it comes down for them to defining precisely what is meant with an "if ... else if construct"

Tamworth answered 3/2, 2016 at 0:17 Comment(2)
There is nothing in MISRA that prevents you using else if - quite the contrary, Rules exist to support it! Disclaimer: Current MISRA C chairman ;-)Blackface
Thank you for the clarification, sir! I have now removed my false claims about MISRA. I checked my sources and found that the document I retained from my time in the automotive industry falsely claimed to constitute the original MISRA C standard from 2004, when in fact, it also included the in-house style guide, which was not marked as such. It was these rules that my original answer was based on. My apologies for the misrepresentation.Tamworth
M
5

Logically any test implies two branches. What do you do if it is true, and what do you do if it is false.

For those cases where either branch has no functionality, it is reasonable to add a comment about why it doesn't need to have functionality.

This may be of benefit for the next maintenance programmer to come along. They should not have to search too far to decide if the code is correct. You can kind of Prehunt the Elephant.

Personally, it helps me as it forces me to look at the else case, and evaluate it. It may be an impossible condition, in which case i may throw an exception as the contract is violated. It may be benign, in which case a comment may be enough.

Your mileage may vary.

Meander answered 28/1, 2016 at 17:1 Comment(0)
S
5

The basic reason is probably code coverage and the implicit else: how will the code behave if the condition is not true? For genuine testing, you need some way to see that you have tested with the condition false. If every test case you have goes through the if clause, your code could have problems in the real world because of a condition that you did not test.

However, some conditions may properly be like Example 1, like on a tax return: "If the result is less than 0, enter 0." You still need to have a test where the condition is false.

Snare answered 28/1, 2016 at 17:33 Comment(0)
B
4

Most the time when you just have a single if statement, it's probably one of reasons such as:

  • Function guard checks
  • Initialization option
  • Optional processing branch

Example

void print (char * text)
{
    if (text == null) return; // guard check

    printf(text);
}

But when you do if .. else if, it's probably one of reasons such as:

  • Dynamic switch-case
  • Processing fork
  • Handling a processing parameter

And in case your if .. else if covers all possibilities, in that case your last if (...) is not needed, you can just remove it, because at that point the only possible values are the ones covered by that condition.

Example

int absolute_value (int n)
{
    if (n == 0)
    {
        return 0;
    }
    else if (n > 0)
    {
        return n;
    }
    else /* if (n < 0) */ // redundant check
    {
        return (n * (-1));
    }
}

And in most of these reasons, it's possible something doesn't fit into any of the categories in your if .. else if, thus the need to handle them in a final else clause, handling can be done through business-level procedure, user notification, internal error mechanism, ..etc.

Example

#DEFINE SQRT_TWO   1.41421356237309504880
#DEFINE SQRT_THREE 1.73205080756887729352
#DEFINE SQRT_FIVE  2.23606797749978969641

double square_root (int n)
{
         if (n  > 5)   return sqrt((double)n);
    else if (n == 5)   return SQRT_FIVE;
    else if (n == 4)   return 2.0;
    else if (n == 3)   return SQRT_THREE;
    else if (n == 2)   return SQRT_TWO;
    else if (n == 1)   return 1.0;
    else if (n == 0)   return 0.0;
    else               return sqrt(-1); // error handling
}

This final else clause is quite similar to few other things in languages such as Java and C++, such as:

  • default case in a switch statement
  • catch(...) that comes after all specific catch blocks
  • finally in a try-catch clause
Basle answered 7/2, 2016 at 8:19 Comment(0)
D
2

Our software was not mission critical, yet we also decided to use this rule because of defensive programming. We added a throw exception to the theoretically unreachable code (switch + if-else). And it saved us many times as the software failed fast e.g. when a new type has been added and we forgot to change one-or-two if-else or switch. As a bonus it made super easy to find the issue.

Dehiscence answered 3/2, 2016 at 4:8 Comment(0)
S
2

Well, my example involves undefined behavior, but sometimes some people try to be fancy and fails hard, take a look:

int a = 0;
bool b = true;
uint8_t* bPtr = (uint8_t*)&b;
*bPtr = 0xCC;
if(b == true)
{
    a += 3;
}
else if(b == false)
{
    a += 5;
}
else
{
    exit(3);
}

You probably would never expect to have bool which is not true nor false, however it may happen. Personally I believe this is problem caused by person who decides to do something fancy, but additional else statement can prevent any further issues.

Sericeous answered 3/2, 2016 at 9:57 Comment(0)
Z
0

I'm currently working with PHP. Creating a registration form and a login form. I am just purely using if and else. No else if or anything that is unnecessary.

If user clicks submits button -> it goes to the next if statement... if username is less than than 'X' amount of characters then alert. If successful then check password length and so on.

No need for extra code such as an else if that could dismiss reliability for server load time to check all the extra code.

Zig answered 2/2, 2016 at 22:16 Comment(1)
This question was written with the 'mirsa' tag. It is automotive safety-critical. I don't think the PHP in question is for that type of application?Kleinstein
K
0

As this question on boolean if/else if was closed as a duplicate. As well, there are many bad answers here as it relates to .

For a boolean, there are only two cases. In the boolean instance, following the MISRA recommendation blindly maybe bad. The code,

if ( x == FALSE ) {
    // Normal action
} else if (x == TRUE ) {
    // Fail safe
}

Should just be refactored to,

if ( x == FALSE ) {
    // Normal action
} else {
    // Fail safe
}

Adding another else increases cyclometric complexity and makes it far harder to test all branches. Some code maybe 'safety related'; Ie, not a direct control function that can cause an unsafe event. In this code, it is often better to have full testability without instrumentation.

For truly safety functional code, it might make sense to separate the cases to detect a fault in this code and have it reported. Although I think logging 'x' on the failure would handle both. For the other cases, it will make the system harder to test and could result in lower availability depending on what the second 'error handling' action is (see other answers where exit() is called).


For non-booleans, there may be ranges that are nonsensical. Ie, they maybe some analog variable going to a DAC. In these cases, the if(x > 2) a; else if(x < -2) b; else c; makes sense for cases where deadband should not have been sent, etc. However, these type of cases do not exist for a boolean.

Kleinstein answered 20/3, 2022 at 19:23 Comment(1)
There is a subtle but very valid point to this answer... in C, false is 0 but true can have any value (it just is usually 1) - eg the <ctype.h> isxxxx functions return non-zero for true. So testing for true is unwise...Blackface

© 2022 - 2024 — McMap. All rights reserved.