An Introduction to Programming
Errors and Debugging
Once you start trying out code snippets or you are trying to solve actual problems with code, you will soon realize that there will be moments when your program breaks, is interrupted and stops running.
This is often caused by errors, known as bugs or exceptions in run-time. The act of finding and removing bugs from our code is debugging. You get better at debugging code as you try doing it more. We do not only debug our own code, we can also debug code written by other programmers.
To get started, we need to identify the common bugs likely to surface in our source code.
These errors will not allow your source code to compile in compiled programming languages. They are detected at compile-time or during the interpretation of your source code. They can also be detected easily by linters. We will learn a little more about linters later.
They are mostly caused when you break the expected form or structure of the language you are coding in. An example is missing a closing bracket in an equation.
Semantic errors also known as logical errors are the most troublesome of all errors. They cannot be easily detected. A sign that there’s a semantic error is when the program runs successfully but does not produce the desired output.
Consider this example:
3 + 5 * 6
By order of precedence, popularly called BODMAS, in Mathematics, we expect the multiplication part to be evaluated first, and then final result will be 33. If the programmer wanted the addition to evaluate first instead, this will give a different output than the desired output. Errors such as this are semantic errors, having more to do with meaning than structure (syntax).
Parenthesis around 3 + 5 will give the desired output of 48 instead.
(3 + 5) * 6
Like semantic errors, run-time errors are never detected at compile time. Unlike semantic errors, run-time errors interrupt the program and prevents it from executing further. They are usually caused by unexpected result of some computation within the source code.
Here’s a good example:
input = 25x = 0.8/(Math.sqrt(input) - 5)
The code snippet above will compile successfully, but an input of 25 will result in ZeroDivisionError. This is a run-time error. Another popular example is the StackOverflowError or IndexOutofBoundError. What is really important is that you identify these errors and learn how to deal with them.
There are errors caused by how your source code makes use of memory and space on the platform or environment in which it is run. They are also run-time errors. Such errors as OutOfMemoryErrorand HeapError are usually caused by how much your source code use up resources. A good knowledge of algorithms will help you write code that better makes use of resources.
The process of rewriting your code for better performance is called optimization , and a not-so-related word is refactoring. As you spend more time coding, you should have these in mind as well.
Here are a few tips on how to go about debugging your code:
Use Linters Linters are tools that help read through your source code to check if they conform the expected standard in the language you are coding in. There are linters for many programming languages. Be sure to get one for the language you are learning.
IDEs over simple editors You could opt for an IDE designed for the language you are learning. IDE stands for Integrated Development Environment. They are software built for writing, debugging, compiling and running code. They usually come with powerful debugging kits, for watching or stepping through your code. Jetbrains make great IDEs such as the Webstorm, and IntelliJ. There’s NetBeans, Komodo, Qt editor, Android Studio, XCode (shipped with Mac) to name a few.
Reading your code aloud This is usually useful when you are looking for a semantic error. While reading your code aloud, there is a high chance you will read out the error as well. That might jump at you as what was probably wrong.
Read error logs When the compiler flags an error, be sure to look at the line number or the part of your code flagged.
As a beginner, you will be learning to code from books, online tutorials or from videos. You will often type down code as you see them.
Here’s something you should do, when you are done writing or running such code, learn to break them. How do you do this?
Change something to see how the code behaves. Do this so that you don’t make assumption about anything and you are pretty sure you understand what is going on.
1 . What’s the likely bug in the Python code snippet below:
items = [0,1,2,3,4,5] print items
//hint: items here is an Array, with 6 items. To retrieve the 4th item for example, you will use items. We start counting from 0.
2. What is the likely bug in the Python code snippet below:
input = Hippo' if input == 'Hippo': print 'Hello, Hippo'
Congratulations! The bug word is no longer a strange one to you, and picking out bugs now should not be either. Next, we will look into the common flow of the code that we write everyday.
Answers to the Quiz
What’s the likely bug in the Python code snippet below: (1) Runtime Error: Index Out of Range Error (2) Syntax Error: Missing starting quotation mark on line 1
Want to add a caption to this image? Click the Settings icon.
Part 4 — Basic Coding Flows
Line Of Code, Expressions and Statements
The unit of any source code is the LOC (Line of Code). The simplest program is a line of Code. A LOC could be a keyword, a symbol, or a statement. It’s a Line of Code as long as it’s on a separate line of its own.
Let us consider a simple line of code:
area = 0.5 * base * height
0.5 * base * height is an expression. An expression is a combination of operators and operands. In the example given here, the operands are 0.5, base, height. You will recall that 0.5 is a floating point literal, base and height are variables. The operator is the *(multiplication).
Expressions may not be meaningful staying on their own as a LOC. When we assign the value of an expression to another variable, in the case above the area, what we have is called a statement. It is still a statement when we attach expressions to keywords, example: return 0.5 * base * height
For the rest of this section, we will represent a statement as the symbol S. The nth statement will be Sn amongst a sequence (or set) of statements
To grasp programming quickly, a good starting point is understanding basic coding flows. Basic flows are also referred to as control flows. Once you understand these flows, you will find them in many of the programming languages you learn.
Note that the examples given in this write-up are purely basic. You need to refer to the language you are learning to get an in-depth knowledge of the keywords it provides.
Also the basic flows introduced here are different from design patterns in programming. Understand these basic flows first. You catch up later with common design patterns in programming as you learn more.
Here are the basic programming flows:
This is the most basic flow, where one statement is executed after the other. In the actual sense, every other flow resolves to a sequential flow (more on this later).
S1 S2 S3 . . . Sn
The statement that executes is determined by conditions. The key keyword here is the if keyword. It’s one of the most used coding flow.
Here’s the simplest conditional pattern:
if (condition) then: S1
In the example above, either S1 executes or nothing happens. S1 is executed only if the condition given is true.
Here’s another conditional pattern:
if (condition) then: S1 S2 else: S3 S4
That can be read as either running of S1-S2 or S3-S4 based on the condition given. If the condition is true, S1 and S2 will be processed. Otherwise the statements S3 and S4 will be processed. This in actual sense is a sequential flow:
We also have the multi-conditional style:
if (condition1) then: S1 else if (condition2) then: S2 else: S3
Here if condition1 is true, then S1 is processed. Otherwise condition2 is tested, and if true, S2 is processed. This can go on and on.
For the multi-conditional style, many programming languages provide the switchstatement. Here’s the pattern for the switch statement:
switch value: case condition1: S1 break case condition2: S2 break
The condition1 and condition2 are compared with the value in the switch statement. If any of them is true to the value, then the statement in the case block is executed.
There are other choices for conditional flow. Some are specific to the language you decide to learn such as the conditional operator (: ?), and other keywords that facilitate branching such as cycle and break. Be sure to spend sometime understanding the condition/branching flow.
The iteration/repetition flow keeps statement(s) running for as long as some conditions are met, and stops executing the statement(s) once the condition is no longer true.
Here’s the pattern:
while (condition): S1 S2
In the example above, statements S1 and S2 may execute once, multiple times, or may not execute at all. If the condition given is true the first time the whilestatement is encountered, then S1 and S2 will be processed. The while condition is checked again, and S1and S2 will be executed for as long as the condition is true.
The moment the condition becomes false the execution of S1 and S2 stops.
The result of statement above if condition is true thrice will be:
S1 S2 S1 S2 S1 S2
What coding flow is that? If you answered sequential, you are very correct. Still as we can see, the other flows resolve to the sequential flow.
Here’s another iteration pattern:
do: S1 S2 while (condition)
In this example, S1 and S2 will execute at lease once or multiple times. This is because they will execute before the condition is tested.
In many programming languages, keywords like the do andwhile are provided for implementing the repetition flow. Another common keyword is the for keyword. Here’s the common pattern for the for statement.
for (initialvalue; condition; decrement/increment initialvalue): S1 S2
Many languages have foreach used for working through each items in a complex object such as an array, or struct.
Identify the coding flows in the following Python code snippet:
numlist= cnt=0 while cnt >= 0: m=int(raw_input()) if m < 0: break numlist.append(m) cnt=cnt+1
The flows covered here are the basic flows. There’s a way to group a bunch of code together and give them a name. This way you may call this bunch of code whenever you need them at once. This is referred to as a procedure. In the case where the bunch of code perform some operation and return a value, you have a function.
How procedures and functions are implemented vary with different languages. You cannot skip these to get the basics of any language. They are highly important for organizing your code. In fact, this is where the building blocks of your code starts also known as modular programming.
There are other flows that you will learn the moment you understand functions, one that comes to mind is recursion.
Yet, you will find that within procedures and functions are still the awesome coding flows we have covered here — sequential, conditional and loops/iterative flow.