Time and time again programmers come on the Dream.In.Code board seeking answers to a problem that they know the steps to solve but just can’t get those steps to work on the computer. They know they need to add 1 to a value until it reaches 27, but how do you do that? A loop you say? But which one? Sometimes the newbie picks the wrong type of implementation to a problem. Here on this entry we will talk a bit about picking the right type of code to meet some common problems right here on the Programming Underground!
What prompted me to write this entry was a question that was asked recently by a brand new programmer looking to implement an incrementation of a value starting at the value 22 and adding 1 until it reaches 27. Sounds pretty simple to the average programmer right? That is half the battle… identifying what type of code you need. Experience tells you that you are looking for a loop. Great, you have solved the first part. However, the second half is actually looking for the “right” choice in loop to create the desired solution. You know you need a loop, but which kind is best? A while loop? A post test type of loop like a do while? Maybe a for loop?
This is where the newbie can really get hung up. The student knew what they wanted to do but couldn’t quite translate the steps into solving the problem. So I have outlined a few common situations where someone might get stuck with a “what code do I use?” type of situation.
1) Iteration. If you need to accumulate a value, move through a collection, continue doing a series of actions over and over again you are going to need a loop. The type of loop you choose depends on a few decisions. First of all, do you know how many times this loop will need to be executed? Is it a specific number like “this loop needs to execute 5 times exactly”? Then you want a for loop because that will allow you to pick a starting point and loop through to an end point. If you are asking yourself “I need these steps to execute while something is true”. The keyword here is “while”. So you need a while loop. But do you have one where the condition is first (a pre-test condition) or a do while loop where you test at the end (post-test condition)? This choice is simple…if it must execute at least once, you want a do while. Otherwise a pre-test while loop is your answer. A loop can always be translated into another type of loop, but always pick the best loop for the current situation.
Other types of loops are typically variations on the basic for/while loops of the past. The foreach loop is really a while loop for collections and keeps looping until it reaches the end (the end being a false condition). The question here would be if your language supports a foreach loop when would it be wise to choose that? The answer is… use a foreach whenever you need to move through a collection until you exhaust the set but not necessarily need to modify everything in the set. That is, you need to keep looping until there are no more objects left. This is great for situations where you just need to print values, search for a value, or otherwise get information from objects in a set.
2) Structure vs Class. This is a HUGE sticking point for both seasoned as well as newbie programmers. Sometimes the language you are working with will determine this for you. Obviously if you are in C programming there is no classes so you have to use a struct. Some professionals will tell you just to go with a class all the time because a structure can be written as a class. This advice will work for a majority of the problems out there, but structs are there for a reason.
But for languages where you have a choice, you have to ask yourself a simple question. “Am I looking to organize data or am I looking to manipulate or gleam information off of data?” If you are just looking to organize some data so it is together as a unit and its pieces of data are easily accessible, won’t need to be put together into new configurations to create “information” or otherwise used for simple operations a structure is probably what you want. Structures are placed on the stack memory for quick access. So if you need something to organize a few numbers, a string, even another structure quickly and simply, use a struct.
Now from experience this typically only accounts for about 5% of the situations out there. That is because you often want that data to be put together into information, acted upon by other code, called upon using methods, manipulated around, presented based on a particular situation or even inherited into other objects later on. If this is the case you will want to use a class. Classes are placed in heap memory because they require a lot of extra information to keep it together as an object and its size is a sum of all its members which can be quite large.
Usually if you are in this situation and not quite sure which to choose, but assume you may add onto it later, choose a class. This will offer you the most flexibility and advantages for expansion later.
3) Series of if-else or a switch/select case. The questions here are “Do I need a bunch of short one line statements?” and “are there a lot of these statements?” If you find yourself using an if statement that seems to go on forever like “if this do that, else if this, do that, else if, do that….” for 20 lines then you might want to consider a switch statement. Switch statements are going to provide you compact code and can be very readable if each case is going to be a simple one or two lines. Another question you might ask yourself is “If I have 5 or 6 I want to do this one statement, 7 I want to do this other statement, and 8 or 9 or 10 do this statement…” then again a switch might be your best bet. It can be better than chaining together long boolean if statement conditions. At least with a switch you can let choices fall through. If 5 fall through to case 6’s code for example.
If you are looking for some conditions that are quick simple and limited to one or two choices, then an if-else statement setup is going to be your ideal choice. Personally if I see the if statements growing to more than 3 or 4 else ifs, I start thinking switch statement.
4) Variables declaration. The question a newbie might ask is “Where do I define this? At the for level?” This is actually a question about variable scope. The rule here is put any variable definitions as close to where they are going to be used as possible. Does the variable need to be used by more than one function? If the answer is yes, then you have one more choice to make. Do you define it in such a place that both functions can see it or do you pass the variable to the other function? Here if the functions work together, pass the variable. If the two functions have nothing to do with one another and one function is never going to call the other function, then make it a higher scope.
Whatever you do though, try to keep them as local as possible. You should have a lot more variables defined inside of functions than you should ever have at a global level.
5) Code needing its own function. When do you split up code? The answers here are “whenever the function gets too long” or “whenever the code appears to start repeating itself”. The first answer is related to readability. A function should never expand more than one whole page. That can be anywhere from 30 – 50 lines. This is not a hard fast rule, but if you are having to scroll to see all of your function, it is obviously cumbersome, harder to read, and harder to manage so split it up. The second answer relates to reusability and refactoring. The idea here is that we keep everything in one place and never repeat yourself. If there is ever a bug in that piece of code then you can fix it in one place instead of having to fix it in multiple places. Fixing in multiple places just increases your chances of making yet another mistake. For those of you who don’t know what refactoring is, one form of it is the process of taking repeating code, ripping it out, placing it in its own function, make it generic in use and then call the function anytime you need that code. That way you can quickly locate the problem in a function, fix it, and have it automatically fixed for all code that references the function.
Got a code tip you want to share with the rest of the readers? Feel free to share it through this entry’s comments and discuss what the question is behind making the choice, the choice options, and which choice might be best for which situations. The more we have here the bigger and better this resource.
Thanks to everyone for reading. 🙂