Control Flow Statements
An important property of a Programming Language for it to be Turing Complete is for its control flow to be able to branch, or jump to a different part of the program. A branching instruction can be in the form of a conditional (
if-then), a loop, a switch statement, or unconditional statements, like
goto, or subroutine calls.
In many high level languages,
if statements or conditionals are used to direct the flow of the control according to a condition evaluated during the execution.
The primary form of an
if statement is the following:
1 2 3
Here, condition is supposed to be something that can be interpreted as a boolean value, i.e, something which can be interpreted as true or false. The
do_something statements are a part of, what is called the if-block.
An usual extension to the
if is the
else, which marks a block that is executed if and only if (no pun intended) the
if block does not execute, i.e, the condition is not met.
1 2 3 4
We could want to check through a series of different conditions, using the
if, in which case we usually nest the
1 2 3 4 5 6 7 8
For an indented language like Python, this does look silly, but its just okay for other languages. For example, in C++:
1 2 3 4 5 6 7 8 9
Luckily for us, there is the
elif statement in Python, which is the shorthand for the same thing.
1 2 3 4 5 6
Another alternate form of the above is the
switch statement in some languages:
1 2 3 4 5 6 7 8 9 10 11
The switch statement checks if the
value matches the particular case. Note that we terminate each case with a
break, without which all of the subsequent code would be executed. This is called a fall-through.
FizzBuzz Problem Looping through the numbers from 1 to N, print the number if it is not divisible by 3 or 5, print "Fizz" if it is divisible by 3, "Buzz" if it is divisible by 5, and "FizzBuzz" if by both.
1 2 3 4 5 6 7 8 9
for i in range(1,N+1): if i%3==0 and i%5==0: print "FizzBuzz" elif i%3==0: print "Fizz" elif i%5==0: print "Buzz" else: print i
goto statements are instructions to jump the execution flow to a labeled statement somewhere else in the program.
1 2 3 4
goto end; std::cout << "This line is never executed" << std::endl; end: std::cout << "Great, now we are at the end" << std::endl;
In the above example, the program never gets to run line 2.
A good way to use
goto is to jump out of a deeply nested loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
To be fair,
goto can be used to replace many other statements including the loops. For example,
1 2 3 4 5 6
//print 1 to 10 int i = 1; top: std::cout << i; i++; if (i <= 10) goto top;
However, this is not the best idea because it leads to what is called spaghetti code: a program in which the control flow is difficult to reason through. Thanks to structured programming, we do not need to resort to this practice any more.
Fun Fact: Computer Scientist Dijkstra published an essay GOTO Statement Considered Harmful in the March 1968 Communications of the ACM explaining why the GOTO statment is best avoided. A criticism of the same was published titled 'GOTO Statement Considered Harmful' Considered Harmful. A further reply was titled "GOTO Considered Harmful" Considered Harmful' Considered Harmful?
Loops as Conditionals
for can also be viewed as branching statements. It is perfectly possible for a while loop to skip the
while block completely, when the condition is not met. This is equivalent to using an
To be clear, these two programs are equivalent:
1 2 3
Also, as we have already discussed, a loop is equivalent to an
if equipped with a
In procedural programming, function calls cause the control flow to jump from the current execution point to the beginnning of the subroutine. Function calls in modern programming languages are a very effective way to orgranize code.
An important point about function calls is that they take up extra memory space. This is because the program needs to store information about where the execution flow should return to once the function is finished executing. Typically, this information is stored in an area of the RAM allocated by the operating system called the stack. Since the size of the stack is usually static, it can be fatal to place too many function calls.
In functional programming languages, the functions are implemented in a similar way in the lower level, although theoretically that is not the correct way to reason about them. In functional programming, functions are supposed to be declarative abstractions, not procedural.
Jump Instuctions in Assembly
This section is incomplete. You can help by editing.
Jump instructions in assembly are much like the
goto in high level languages. They allow the programmer to set the value in the Instruction Pointer register.
They are either unconditional jumps (
jmp), or jumps on equality, inequality, if greater, less, when overflow, etc.