Switch statement into while loop or while loop into case blocks? - refactoring

I'm refactoring some code I wrote and I have to decide if I wanna put a switch statement into a while loop or repeat the while loop into each case blocks. The two different ways are something like the following pseudocode:
Option 1)
while (cnt > 0) {
switch (value) {
case A:
doSomething();
break;
case B:
doSomethingElse();
break;
...
default:
default();
break;
}
cnt--;
}
Option 2)
switch (value) {
case A:
while( cnt > 0){
doSomething();
cnt--;
}
case B:
while( cnt > 0){
doSomethingElse();
cnt--;
}
...
default:
while( cnt > 0){
default();
cnt--;
}
}
I think the first option follows better the DRY principle because I don't repeat every time the while and the cnt--. Although I like a bit better the second option because once it picks a case in the switch statement, it starts to loop in the while and it doesn't have to evaluate the switch condition anymore.
So, which of these two solutions would you pick and why?
NB: We can assume that the switch-condition (i.e. the variable "value" in the code below) doesn't change for the entire while loop, in other words: the operations doSomething(), doSomethingElse() etc. do not affect the switch statement.
NB2: In the real code I'm working on, the while loop can be very huge. "Cnt", for some test cases, can be of the order of 10^9

In most cases, a Loop-switch sequence is an antipattern you should avoid for the sake of clarity, and since you mention cnt can become quite huge also for the sake of performance.

If cnt is used only to control how many times doSomething(), etc., are called, you should consider passing it into the method and looping inside the method. Normally I would say don't worry about performance, but if you're actually talking about 10^9 iterations, you should avoid repeating the switch.

Option 2 is more straightforward as you are putting the emphasis on the switch-statement and having to work through a case in every iteration might consume more time.

Related

golang's fallthrough seems unexpected

I have the following code:
package main
import (
"fmt"
)
func main() {
switch {
case 1 == 1:
fmt.Println("1 == 1")
fallthrough
case 2 == 1:
fmt.Println("2 == 1")
}
}
Which prints both lines on the go playground - see example here. I would have expected the fallthrough statement to include evaluation of the next case statement, but this seems not to be the case.
Of course, I can always use a bunch of if statements, so this is not a real impediment, but I am curious what the intention here is, since this seems to me to be a non-obvious result.
Anyone care to explain? For example: in this code, how can I get the 1st and 3rd cases to execute?
Switch is not a bunch of ifs. It's more akin to if {} else if {} construct, but with a couple of twists - namely break and fallthrough. It's not possible to make switch execute first and third cases - a switch does not check each condition, it finds first match and executes it. That's all.
It's primary purpose is to walk through a list of possible values and execute a different code for each value. In fact, in C (where switch statement came from) switch expression can only be of integral type and case values can only be constants that switch expression will be compared too. It's only relatively recently, languages started adding support for strings, boolean expressions etc in switch cases.
As to fallthrough logic it also comes from C. There is no fallthrough operator in C. In C execution falls through into next case (without checking case values) unless break operator encountered. The reason for this design is that sometimes you need to do something special and then do same steps as in another case. So, this design merely allows that. Unfortunately, it's rather rarely useful, so falling through by default was causing more trouble when programmer forgotten to put a break statement in, then actually helping when truly omitted that break intentionally. So, many modern languages change this logic to never fall through by default and to require explicit fallthrough statement if falling through is actually required.
Unfortunately, it's a it hard to come up with a non contrived example of fallthrough being useful that would be short enough to fit into an answer. As I said it's relatively rare. But sometimes you need to write code similar to this:
if x == a || x == b {
if x == a {
// do action a
}
// do action ab
} else if x == c {
// do action c
} else if x == d {
// do action d
}
In fact, I needed code of similar structure quite recently in one of my projects. So, I used switch statement instead. And it looked like this:
switch x {
case a: // do action a
fallthrough
case b: // do action ab
case c: // do action c
case d: // do action d
}
And your switch from the question is functionally equivalent to this:
if 1 == 1 || 2 == 1 {
if 1 == 1 {
fmt.Println("1 == 1")
}
fmt.Println("2 == 1")
}
Presumably, Go's fallthrough behavior is modeled after C, which always worked like this. In C, switch statements are just shorthands for chains of conditional gotos, so your particular example would be compiled as if it was written like:
# Pseudocode
if 1 == 1 goto alpha
if 2 == 1 goto beta
alpha:
fmt.Println("1 == 1")
beta:
fmt.Println("2 == 1")
As you can see, once execution enters the alpha case, it would just keep flowing down, ignoring the beta label (since labels by themselves don't really do anything). The conditional checks have already happened and won't happen again.
Hence, the non-intuitive nature of fallthrough switch statements is simply because switch statements are thinly veiled goto statements.
From the language spec:
A "fallthrough" statement transfers control to the first statement of the next case clause in an expression "switch" statement. It may be used only as the final non-empty statement in such a clause.
That seems to perfectly describe your observed behavior.

How can I handle System.StackOverflowException?

This error appears sometimes only when I call a recursive function of which one of the parameters is a number: rand()%10. Just like in the code down below:
private: System::Void AIrandomMove(int randomMove,String ^s)
{
if (randomMove == 1)
{
if ( Move(1) ) // move number 1 had already been done
AIrandomMove(rand()%10,s); // here it appears the System.StackOverflowException
else
//do move number 1
}
//same goes for ==2 || ==3 || ... || ==10
}
How can I handle this?
A proper recursive algorithm works under two assumptions:
you have a base case which terminate the recursion (so the function doesn't call itself)
you have a recursive case which invokes the function itself with different arguments so that there is some progression involved
This translates in something like:
void recursive(inArgs) {
if (condition)
return;
else
recursive(outArgs)
}
It's clear that if condition is the expression true then this code never terminates (hence it will eventually raise a stack overflow).
In your situation condition is evaluated through a random value comparison. Now, assume condition is rand()%2 == 0. So basically each time it is evaluated you have 50% chance of being true and 50% of being false.
This doesn't guarantee that the recursion will terminate, as a path with n true evaluation exists (and it probability can be calculated). That's the problem with your design.
If many moves have been already made (or maybe all of them) then recursion won't end.
You don't need recursion at all in your case, since you could store the available moves in a set and remove them once they are not available anymore (possibly shuffling the set to then choose one randomly). Or even a simpler solution would be something like:
int choosenMove = rand()%10;
while (Move(choosenMove)) {
choosenMove = rand()%10;
// do move choosenMove
}
But this doesn't guarantee termination neither if you don't make sure that a state in which no moves are available can't happen.

Two semicolons inside a for-loop parentheses

I'm customising a code I found over the internet (it's the Adafruit Tweet Receipt). I cannot understand many parts of the code but the most perplexing to me is the for-loop with two semicolons inside the parentheses
boolean jsonParse(int depth, byte endChar) {
int c, i;
boolean readName = true;
for(;;) { //<---------
while(isspace(c = timedRead())); // Scan past whitespace
if(c < 0) return false; // Timeout
if(c == endChar) return true; // EOD
if(c == '{') { // Object follows
if(!jsonParse(depth + 1, '}')) return false;
if(!depth) return true; // End of file
if(depth == resultsDepth) { // End of object in results list
What does for(;;) mean? (It's an Arduino program so I guess it's in C).
for(;;) {
}
functionally means
while (true) {
}
It will probably break the loop/ return from loop based on some condition inside the loop body.
The reason that for(;;) loops forever is because for has three parts, each of which is optional. The first part initializes the loop; the second decides whether or not to continue the loop, and the third does something at the end of each iteration. It is full form, you would typically see something like this:
for(i = 0; i < 10; i++)
If the first (initialization) or last (end-of-iteration) parts are missing, nothing is done in their place. If the middle (test) part is missing, then it acts as though true were there in its place. So for(;;) is the same as for(;true;)', which (as shown above) is the same as while (true).
The for loop has 3 components, separated by semi-colons. The first component runs before the looping starts and is commonly used to initialize a variable. The second is a condition. The condition is checked at the beginning of each iteration, and if it evaluates to true, then the code in the loop runs. The third components is executed at the end of the loop, before another iteration (starting with condition check) begins, and is often used to increment a variable.
In your case for(;;) means that it will loop forever since the condition is not present. The loop ends when the code returns or breaks.
Each clause of a for loop is optional. So when they are excluded, it still loops. for loops compile into while loops.
The end result becomes a check to initialize any variables, which concludes after nothing happening since it is empty, a check to the boolean condition in the second clause, which is not present so the loop starts, and once the loop hits the end bracket, a check to see if there is any code to run before checking the boolean condition again.
In code it looks like:
while(true){
}
Here's What Wikipedia Says About it
Use as infinite loops
This C-style for-loop is commonly the source of an infinite loop since the fundamental steps of iteration are completely in the control of the programmer. In fact, when infinite loops are intended, this type of for-loop can be used (with empty expressions), such as:
for (;;)
//loop body
This style is used instead of infinite while(1) loops to avoid a type conversion warning in some C/C++ compilers.Some programmers prefer the more succinct for(;;) form over the semantically equivalent but more verbose while (true) form.

Automated GOTO removal algorithm

I've heard that it's been proven theoretically possible to express any control flow in a Turing-complete language using only structured programming constructs, (conditionals, loops and loop-breaks, and subroutine calls,) without any arbitrary GOTO statements. Is there any way to use that theory to automate refactoring of code that contains GOTOs into code that does not?
Let's say I have an arbitrary single subroutine in a simple imperative language, such as C or Pascal. I also have a parser that can verify that this subroutine is valid, and produce an Abstract Syntax Tree from it. But the code contains GOTOs and Labels, which could jump forwards or backwards to any arbitrary point, including into or out of conditional or loop blocks, but not outside of the subroutine itself.
Is there an algorithm that could take this AST and rework it into new code which is semantically identical, but does not contain any Labels or GOTO statements?
In principle, it is always possible to do this, though the results might not be pretty.
One way to always eliminate gotos is to transform the program in the following way. Start off by numbering all the instructions in the original program. For example, given this program:
start:
while (true) {
if (x < 5) goto start;
x++
}
You could number the statements like this:
0 start:
1 while (x < 3) {
2 if (x < 5) goto start;
3 x++
}
To eliminate all gotos, you can simulate the flow of the control through this function by using a while loop, an explicit variable holding the program counter, and a bunch of if statements. For example, you might translate the above code like this:
int PC = 0;
while (PC <= 3) {
if (PC == 0) {
PC = 1; // Label has no effect
} else if (PC == 1) {
if (x < 3) PC = 4; // Skip loop, which ends this function.
else PC = 2; // Enter loop.
} else if (PC == 2) {
if (x < 5) PC = 0; // Simulate goto
else PC = 3; // Simulate if-statement fall-through
} else if (PC == 3) {
x++;
PC = 1; // Simulate jump back up to the top of the loop.
}
}
This is a really, really bad way to do the translation, but it shows that in theory it is always possible to do this. Actually implementing this would be very messy - you'd probably number the basic blocks of the function, then generate code that puts the basic blocks into a loop, tracks which basic block is currently executing, then simulates the effect of running a basic block and the transition from that basic block to the appropriate next basic block.
Hope this helps!
I think you want to read Taming Control Flow by Erosa and Hendren, 1994. (Earlier link on Google scholar).
By the way, loop-breaks are also easy to eliminate. There is a simple mechanical procedure involving the creating of a boolean state variable and the restructuring of nested conditionals to create straight-line control flow. It does not produce pretty code :)
If your target language has tail-call optimization (and, ideally, inlining), you can mechanically remove both break and continue by turning the loop into a tail-recursive function. (If the index variable is modified by the loop body, you need to work harder at this. I'll just show the simplest case.) Here's the transformation of a simple loop:
for (Type Index = Start; function loop(Index: Type):
Condition(Index); if (Condition)
Index = Advance(Index)){ return // break
Body Body
} return loop(Advance(Index)) // continue
loop(Start)
The return statements labeled "continue" and "break" are precisely the transformation of continue and break. Indeed, the first step in the procedure might have been to rewrite the loop into its equivalent form in the original language:
{
Type Index = Start;
while (true) {
if (!Condition(Index))
break;
Body;
continue;
}
}
I use either/both Polyhedron's spag and vast's 77to90 to begin the process of refactoring fortran and then converting it to matlab source. However, these tools always leave 1/4 to 1/2 of the goto's in the program.
I wrote up a goto remover which accomplishes something similar to what you were describing: it takes fortran code and refactors all the remaining goto's from a program and replacing them with conditionals and do/cycle/exit's which can then be converted into other languages like matlab. You can read more about the process I use here:
http://engineering.dartmouth.edu/~d30574x/consulting/consulting_gotorefactor.html
This program could be adapted to work with other languages, but I have not gotten than far yet.

What is the correct way to convert from a for loop to a while loop?

I have a for loop of the form:
for (int i = from; i < to; i++) {
// do some code (I don't know exactly what, it is subject to change)
}
And I want to convert it to a while loop (mostly because I want to play with the value of i inside the loop to go backwards and forwards and my co-worker thinks that doing this in a for loop is prone to problems. I tend to agree with him). So I wrote something like this:
int i = from;
while (i < to) {
try {
// do some code (I don't know exactly what, it is subject to change)
} finally {
i++;
}
}
Which prompted some some loud comments. My reasoning is that you don't know what the code inside the loop does - it may (and does) have multiple continue commands.
As a response he wrote this:
int i = from - 1;
while (++i < to) {
// do some code (I don't know exactly what, it is subject to change)
}
Granted its less lines, but I still think my code is more elegant - what do you think?
Playing with the value of your index while in a looping structure is prone to problems, no matter what the looping structure is.
It's not going to matter if it's a for loop or a while loop, the point is will the indexer eventually lead you to make a decision of loop termination?
If you're confident that you're indexer will eventually cause your exit condition to be achieved, then that is all you should be concerned with, not whether to use a for or a while.
And I want to convert it to a while loop (mostly because I want to play with the value of i inside the loop to go backwards and forwards and my co-worker thinks that doing this in a for loop is prone to problems. I tend to agree with him).
This is perfectly acceptable in most languages. There is no reason to avoid a for loop.
It seems to me that it may be easier and more readable to convert it to:
while (condition == true) {
// do stuff
// set the condition flag appropriately
}
and thus separate the termination of the loop from the variable incrementation.
If I see a loop with a limit check (e.g. i < limit) I would tend to assume that there's a variable that is being modified in a (reasonably) consistent fashion. There's no reason why you can't do what you want, but I would lean towards the more readable and more expected behaviour.
Why bother with silly loops when you can do the same (and much more!) with the uber-powerful goto?
i = fro;
my_loop:
//all your stuff here
i++;
if (i < to) goto my_loop;
If you are one of those faint hearted programmers that diminish the goto, then you can try with this:
i = fro;
while(1) {
//your stuff here
if (++i < to) break;
}
The easiest way to do this would be to not convert into a while loop, such as below.
for (int i = from; i < to; ) {
// do some code (I don't know exactly what, it is subject to change)
i += rand()*10;
}
To answer the question about which code I would select; I choose your longer code. Its MUCH easier to read the first(longer) loop. And yes I can read the second but even if you have lots of experience you have to look twice to know what that loop does. Plus the compiler will optimize the code well enough.

Resources