Jump to content

  • Log In with Google      Sign In   
  • Create Account


alternatives to long else if and switch statements


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
16 replies to this topic

#1 BloodOrange1981   Members   -  Reputation: 214

Like
0Likes
Like

Posted 10 June 2013 - 04:13 AM

I`m working on a project where there is a massive amount of library/engine files being used from the last project. In quite a few there are crazily long if-else and even nested trailing if-else statements making some changes hard to debug and sometimes it`s hard to see where the missing curly bracket is on compiling errors.

 

So I`d like to know about some valid alternatives. Obviously there`s the switch statement, but that would also get unmanageable by being overly long and nested too. 

 

I was thinking of arrays of function pointers indexed by case, but in a non-deterministic program surely this would cause program execution to jump all over the place and was wondering on the impact on performance.

 

Obviously, like many things you can never have it all, something will suffer as a consequence of the benefit of something else but are there any suggestions?

 

Thanks



Sponsor:

#2 rip-off   Moderators   -  Reputation: 7691

Like
2Likes
Like

Posted 10 June 2013 - 04:36 AM

I was thinking of arrays of function pointers indexed by case, but in a non-deterministic program surely this would cause program execution to jump all over the place and was wondering on the impact on performance.

If this is what your program needs to do, then that is what it needs to do. If it doesn't need to do it, then don't! If profiling indicates that this is a critical inner loop, consider if the inputs can be sorted, so that each batch of similar inputs takes a similar path.

 

A long, contiguous switch statement can be optimised by the compiler to the equivalent of this array of function pointers, called a "jump table".

 

What kinds of situations do these "crazily long" chains appear in? Concrete examples are usually much easier to talk about, and have the benefit of hinting at high level changes in approach that are far less obvious when talking about abstract situations.



#3 NightCreature83   Crossbones+   -  Reputation: 2674

Like
0Likes
Like

Posted 10 June 2013 - 05:03 AM

You could off course go with a state machine that does the switch changing in a polymorphic manner if they share enough common code to deal with that approach. Often looks nicer and is off course easier to control and extend in the long run.

 

As a side note here is how a 5 case switch statement looks in unoptimised C++: http://www.altdevblogaday.com/2012/04/10/cc-low-level-curriculum-part-7-more-conditionals/


Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, Mad Max

#4 rnlf   Members   -  Reputation: 1095

Like
0Likes
Like

Posted 10 June 2013 - 05:49 AM

In this case I would not yet care too much about performance. Primary target should always be readability and maintainability of your code. At work, I have to deal with legacy code containing, in multiple places, switch statements and deeply nested if statements with in some cases more than 5000 LOC. This is a programmer's nightmare come true.

Write the simplest, most easily maintainable version you can think of (using a function pointer table or inheritance) and use that, until you have some evidence (i.e. after you have profiled your code) that this has a measurably bad impact on your program's overall performance.


my blog (German)


#5 Felix Ungman   Members   -  Reputation: 899

Like
1Likes
Like

Posted 10 June 2013 - 06:10 AM

I`m working on a project where there is a massive amount of library/engine files being used from the last project. In quite a few there are crazily long if-else and even nested trailing if-else statements making some changes hard to debug and sometimes it`s hard to see where the missing curly bracket is on compiling errors.

 

As rnlf points out, readability should be the primary goal. Some techniques:

 

- Remove reduntant conditions (the most extreme being if (x) … else if (!x) …", but there are other more subtle ones). 

- Move the conditions inside the "if(…)" into separate functions. Try to find good names for those functions.

- Move the statements inside the brackets into separate functions. Try to find good names for those functions.

- Sarch for code duplication inside those conditions and statements and put that into separate functions too. Try to find good names for those functions.

- Try to keep the if-elseif-…-else chain consistent. Sometimes it's more logical to split one long chain into two separate ones. Sometimes you can merge two chains into one.


openwar  - the real-time tactical war-game platform


#6 Álvaro   Crossbones+   -  Reputation: 11915

Like
3Likes
Like

Posted 10 June 2013 - 07:09 AM

With more information on what that piece of code is doing, it would be possible to suggest more appropriate solutions.

 

At the very least, one big switch statement is more expressive and possibly faster to execute than a long if-else if-...-else chain. Function pointers, signals and slots, and polymorphism are all similar constructs that might be good alternatives, depending on what the code is doing.



#7 jwezorek   Crossbones+   -  Reputation: 1623

Like
1Likes
Like

Posted 10 June 2013 - 10:23 AM

It is hard to suggest solutions without seeing the actual code, but generally:

 

  1. If the code could possibly be a switch-statement then a switch statement would be better than an if-else chain
  2. The code in the case handlers of the switch statement can be easily broken out into functions and if there is a lot of it this is probably a good idea.
  3. If you can do 1. and 2. then it is also possible to set it up as a hash table mapping from values of whatever you are switching on to instances of some kind of handler object, which could just be function pointers/functors but also could be some object that has state if that makes sense.
  4. If it's possible to do 1, 2, and 3 then you could also probably skip the hash table and do the switch functionality as a polymorphically called method of something like the handler objects in 3. 


#8 BGB   Crossbones+   -  Reputation: 1545

Like
0Likes
Like

Posted 10 June 2013 - 04:32 PM

FWIW: IME, a more direct jump through a function pointer can actually be notably faster than going through a long if/else chain, and in-fact in some cases I have actually used function pointers to optimize cases like this (where what would normally require such a long chain can be statically determined to have a particular result, and so a direct jump to the result-logic can be used instead).

 

but, yeah, unless performance is a big issue here, it should probably be more about code organization and readability than about performance though.



#9 BloodOrange1981   Members   -  Reputation: 214

Like
0Likes
Like

Posted 10 June 2013 - 11:27 PM

In this case I would not yet care too much about performance. Primary target should always be readability and maintainability of your code. At work, I have to deal with legacy code containing, in multiple places, switch statements and deeply nested if statements with in some cases more than 5000 LOC. This is a programmer's nightmare come true.

Write the simplest, most easily maintainable version you can think of (using a function pointer table or inheritance) and use that, until you have some evidence (i.e. after you have profiled your code) that this has a measurably bad impact on your program's overall performance.

 

Exactly the kind of situation I`m facing. My colleague thinks it`s super ugly too, and thinks the company we`ve inherited it from must have had some super eccentric coders. 300 line functions and 15000 line files. Crazy. It`s even worse when you have to insert #defines and #ifdefs in between it all to handle seperate formats. 

 

Thanks for the advice, and good luck to you with your code too!



#10 BloodOrange1981   Members   -  Reputation: 214

Like
0Likes
Like

Posted 10 June 2013 - 11:29 PM

Thanks to everyone for the advice, but due to the sheer length and size of the legacy code it will probably be best just to soldier on. However, if I ever had to start a new project from scratch with many conditionals, to avoid this current situation I will keep all of your tips and handy hints in mind.

 

As for code examples, I feel a little apprehensive about cutting and pasting production code on a public forum!

 

Thanks again



#11 Felix Ungman   Members   -  Reputation: 899

Like
0Likes
Like

Posted 11 June 2013 - 12:04 AM

From my experience with working with large and ugly legacy code bases, the most important thing is to use a really good IDE that lets you browse and nagivate the code with ease. And even more important, lets you easily refactor the code and be 100% confident about it. I usually take some time and just sit down with the code and refactor for two reasons.

1) To get a better overview and understanding of the code.

2) New code makes bad code worse, but refactoring can only make it better. Being a good boy scout, you need to refactor enough to at least balance the amount of new code you plan on adding.


openwar  - the real-time tactical war-game platform


#12 rnlf   Members   -  Reputation: 1095

Like
0Likes
Like

Posted 11 June 2013 - 01:11 AM

Felix: Usually I would do exactly the same, the only problem is, every single changed line needs to pass through an engineering board and needs to be justified (in terms of time/money invested) and since in the eyes of the main contractor we are doing only sustaining engineering (i.e. fix major bugs, not add features) this is hard to communicate.

 

BloodOrange1981:

As for code examples, I feel a little apprehensive about cutting and pasting production code on a public forum!

 

Yeah, don't do that. Might get you fired.


Edited by rnlf, 11 June 2013 - 01:11 AM.

my blog (German)


#13 jwezorek   Crossbones+   -  Reputation: 1623

Like
0Likes
Like

Posted 11 June 2013 - 10:41 AM

 every single changed line needs to pass through an engineering board and needs to be justified (in terms of time/money invested) 

 

Then you are basically screwed ... your hands are tied assuming that you personally aren't in a situation in which you can talk directly with the client (or whoever is paying for your time). I mean, the thing to do is have someone explain to whoever is paying for the maintenance work you are supposed to be doing that it might ultimately cost less to do the right thing and touch more code now then to screw around making little patches for the rest of time. 



#14 rnlf   Members   -  Reputation: 1095

Like
0Likes
Like

Posted 11 June 2013 - 03:06 PM

Yeah, the contractual and technical situation is a bit weird. We are maintaining a small part of one of the scientific racks aboard the international space station. If we make mistakes, lose communication and need an astronaut to fix the error, it may well cost the agency (which is the the customer in the end) more than a few of my annual salaries. So we do lots and lots of testing and requirements tracking and meetings for every little change, which in turn costs a lot of time and money. But I don't think this belongs here...


Edited by rnlf, 11 June 2013 - 03:07 PM.

my blog (German)


#15 Felix Ungman   Members   -  Reputation: 899

Like
0Likes
Like

Posted 11 June 2013 - 11:24 PM

Yes, many of the agile practices depend on each other. If you can't release early and release often, and where it's not possible to reduce the cost of mistakes, then you have to rethink the other parts of the process too.


openwar  - the real-time tactical war-game platform


#16 iMalc   Crossbones+   -  Reputation: 2260

Like
0Likes
Like

Posted 12 June 2013 - 02:27 AM

It completely depends on just what code is in that switch statement. Switch statements are often not the best solution.

 

If your switch statement has the same kind of code in each case e.g. imagine a function that turned the numbers 1 to 7 into the strings "Monday" to "Sunday". The best option there is to use a table lookup.

It is primarily when the code for each case is fundamentally doing different things that a switch is likely the best tool.

Even then there are cases where the virtual dispatch mechanism is a more appropriate thing to use. E.g. instead of switching based on RTTI.

 

As for long else-if chains, generally if a single switch statement is at all possible then it is the better option.


"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

#17 wack   Members   -  Reputation: 1229

Like
0Likes
Like

Posted 13 June 2013 - 04:41 PM

 

In this case I would not yet care too much about performance. Primary target should always be readability and maintainability of your code. At work, I have to deal with legacy code containing, in multiple places, switch statements and deeply nested if statements with in some cases more than 5000 LOC. This is a programmer's nightmare come true.

Write the simplest, most easily maintainable version you can think of (using a function pointer table or inheritance) and use that, until you have some evidence (i.e. after you have profiled your code) that this has a measurably bad impact on your program's overall performance.

 

Exactly the kind of situation I`m facing. My colleague thinks it`s super ugly too, and thinks the company we`ve inherited it from must have had some super eccentric coders. 300 line functions and 15000 line files. Crazy. It`s even worse when you have to insert #defines and #ifdefs in between it all to handle seperate formats. 

 

Thanks for the advice, and good luck to you with your code too!

 

This kind of stuff is par for the course in old code bases. Stuff might have started out small, and then people keep on adding stuff through the years as requirements change, features are added, and bugs are fixed.

 

Everyone thinks the code sucks, including those who wrote it, but they find comfort in convinving themselves that they "will refactor in the future". The truth is that that day will probably never come.

 

The upside is that this is all manageable with a good IDE that has nice code browsing features, code folding, etc.

 

The best advice I can give, is just leave it alone and learn to deal with it. If the product is worth anything, there should quite frankly be better things to do than to than to restructure IF-statements.

 

If you want to rewrite it, you should be able to demonstrate (with cold hard numbers) that it will in fact save time or money to rewrite it. Otherwise it's just programmer masturbation.


Edited by wack, 13 June 2013 - 04:45 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS