Errors

Exception handling – inevitably, something will go wrong. That’s why your code has to be able to handle it. An error, also called an exception, is when something bad happens. Exception handling is thinking of a what-if scenario about how things won’t go the way they’re supposed to. Maybe you’re trying to open a file, but what if it doesn’t exist? Implement exception handling for an IOerror.

Here is an example taken from a bigger program I wrote in Python:

def check_if_setup_has_been_completed(project_name):

try:

with open(‘projects/’ + project_name + ‘/settings/finished_initial_setup.txt’) as setup_file:

finished_bool = setup_file.readline()

return eval(finished_bool) # string to bool, True = finished the setup already, False = never done setup

except IOError:

print(“Error: failed initialization check”)

sys.exit()

In Python, it’s called try/except. In other languages, it might be try/catch. Or even try/catch/finally. The try block contains the risky code that might not work as planned. The catch or except part is what happens when you encounter the problem you’re anticipating. finally is what happens at the end. When you catch an error, an exception is thrown.

In the above code example, the program is performing file IO by opening a file and reading from it, and there can be problems with IO, such as a file not existing or having no lines in it. I use the IOError exception to deal with it. Sometimes, you can be lazy and throw very generic errors, but other times, you might want to deal with exceptions in a more specific way. If there are multiple specific errors that you want to handle differently, then you would use more specific exceptions. In some languages, you can make your own custom exceptions, but I don’t recommend that for beginners.

Syntax – syntax is the set of lexical rules that comprise a programming language: punctuation, keywords, order, that kind of thing. Often times, programming languages will have the same general design features, especially if they’re of the same paradigm. But the difference lies in built-ins and syntactic sugar. Analysis of syntax is called lexing or lexical analysis.

Here is a print statement in Java:

System.out.println(“Hello”);

Here is the equivalent in C++:

cout << “Hello” << endl;

And in bash:

echo Hello

And here is the same thing in Python 3 (the current version of Python):

print(“Hello”)

Here is Python 2 (obsolete, don’t use it):

print “Hello”

And something similar in JavaScript:

console.log(“Hello”);

Or even

alert(“Hello”);

These all accomplish similar things, but the syntax is different for each one.

Syntax error – when the syntax of your code is invalid, your IDE or Python interpreter will tell you that something is wrong. These are the most straightforward kinds of issues to deal with.

Compile-time error – an error that occurs when you’re trying to compile your code, and your compiler warns you about a potential problem. Sometimes, a compiler will only issue a warning rather than stop you from compiling entirely. Still not good though.

Run-time error – if your code is fine when it’s compiled, but there is an issue that occurs only when the program is run, then that’s called a run-time error. Maybe your program deals with reading from a file, but the file you’re using is corrupted, not formatted correctly, or just plain missing.

Logic error – you can have errors that are still syntactically valid and don’t cause the program to crash. Sometimes, you can implement the logic of your program incorrectly, and the computer won’t know what you’re trying to do because it will only run your code literally and not try to guess what you actually meant to do. Maybe you wrote a math formula function and used the wrong operator somewhere, like a plus sign instead of a minus. Then the program is valid, but based on your criteria in your head, or in your unit tests, there is an error with the logic.

Off-by-one error – a common error you will encounter is being off-by-one. Maybe you wrote a loop that loops while x < 5 when you really meant to write x <= 5, or vice versa. Being off by one iteration can mean trying to parse past the end of a file, doing something too much, doing something too little, or something like that. It’s essential to look at your loops and make sure they’re right. Depending on the kind of bug you’re encountering, it could be the source of your trouble.

Infinite loop – if you mess up your code, you might end up with a loop that goes on forever.

Here is a loop that will end:

for (int i = 1; i <= 10; i++){

System.out.println(i);

}

Here is what an accidental infinite loop might look like:

for (int i = 1; i >= 10; i–){

System.out.println(i);

}

The iterator variable i will never be equal to or greater than 10 because it’s decremented every loop, so it will never exit.

If you run into an infinite loop, hit ctrl+c or ctrl+x to end your program.

Integer overflow – numeric types have a limit to how big their values can be. For a 32-bit signed integer, you have 231-1 as the greatest value, because one bit is used for signing (positive vs. negative), and then the rest is for the value itself. That amounts to around 2 billion. 2,147,483,647 to be exact. But if you have the maximum value and add one to it, you can loop around back to negatives. This is called an overflow. Sometimes people will call it an integer overflow, other times it’s called a numeric overflow, especially because integers aren’t the only numeric type that can be affected by it. Some languages have protections built in to prevent this stuff, while others do not.

You will notice that newer languages that have better features for convenience and safety (such as protecting against overflows) are often slower. Python is slower than C++. So sometimes, people will prefer to use more primitive and hands-off languages, even if they’re rougher around the edges, just because it means their code can run faster. But it’s a tradeoff between convenience/safety and speed.

Integer underflow – similar to an overflow, an underflow is when a value is so low that it becomes enormous. You go from a negative number in the billions to a positive number in the billions when you subtract a number from it that exceeds that lowest value possible for a given numeric type.

Input validation – making sure that something provided to you by a user is what it’s supposed to be. Very important for security and stability.

You might not be able to trust what the user provides to you. They might not necessarily be malicious, but they might just be giving you incorrect or invalid information. For example, spaces in a folder name can cause problems, and slashes designate subdirectories, which is confusing in a file path. Also, . means the current directory, whereas .. means the parent directory relative to the current working directory. If you don’t validate things like that, you can end up with path traversal bugs, which, for a networked application, are serious security issues that can lead to people grabbing things like ../../../../../../../etc/passwd or ../../../../../../../etc/shadow, which is not good.

Other examples of needs for input validation include SQL injection, overflows, fuzzing, insecure deserialization, and “trust zones” (that assume certain input has already been validated and is now trustworthy if it made it that far).

Code completion – how an IDE or text editor helps you code faster. It’s basically like autocorrect or autocomplete but for code instead of normal words. Microsoft calls their code completion IntelliSense.

← Previous | Next →

Intermediate CS Topic List

Main Topic List

Leave a Reply

Your email address will not be published. Required fields are marked *