How to avoid NULL pointers

Most programming languages (though not all) have the concept of null pointers or references. The most common languages to use null pointers are C/C++ (Java has null references, which are similar). Null pointers cause big headaches to developers because accessing one of them causes crashes or nasty exceptions, which are always associated to a programming defect.

Despite the problems with null pointers, they have valid uses such as checking if an operation finished correctly, or marking a particular value as unknown.

Even though it is possible to find legitimate uses for null pointers, they are not strictly necessary and may lead to unnecessary bugs. Here are some suggestions that can be used to reduced the number of null pointers. Using such suggestions depends on the programming style one wants to use (for example, some people are not concerned with checking null values). However, it is good to know some alternatives to existing practices.

Avoid Variables That Have Dual Meaning

Most of the problems with null pointers arise from functions where the return value has dual meaning. For example, a function may read some data from a file and return a pointer to the data structure or null if there was a problem.

It is clear that the return value here has a dual purpose: it may store a pointer to data, or a null value that signals a problem.

It understandable that some functions are easier to express using this arrangement. However, it may make your program unsafe, especially if there is a possibility that the caller forgets to test the return value.

An alternative to this use of null pointers is to create a separate parameter that stores an error code when the problem happens. This way you don’t need to have a null pointer to represent errors, and you can even have a better description of the error that actually occurred.

Use a Separate Value to Represent Unknowns

Another alternative to null pointers is to use a non-null, unique value that can be employed to represent an unknown element of the domain. For example, if you have a data structure that represents employees, you could create a singe, concrete object that can be used to represent an unknown employee.

An advantage of using this approach is that whenever you see a null pointer of that type if must mean an error. As such, null pointers are not propagated throughout the program, unless a real defect exists in your program.

Another advantage of this approach is that you don’t need to check for null pointers when calling functions and methods of such type. Since you already known that the underlying type is always non-null, you can call functions and methods directly. For example, if you are using C++ or Java, you can use

myObject.myMethod();

without even checking if myObject is null. Similar approaches can also work for C and related languages.

Using this approach, testing if an object is of the unknown type is just as easy as testing for null. Since the unknown object is unique, you can just check if the address is the same, which is almost as quick as testing for null (it may be slightly slower because, in most processors, it is faster to check against zero than other values).

Conclusion

Null pointers have advantages and disadvantages. However, they are not the only way to check for errors and special circumstances in a program. Alternative methods may make your program easier to write and avoid a number of problems associated with null pointer access.

Further Reading

C++ Pointers and Dynamic Memory Management, by Michael C. Daconta, discusses several issues related to pointers in languages such as C and C++. However, it has several ideas that are equally applicable to programmers in Java and C# as well.

Memory as a Programming Concept in C and C++, by F. Frank, is another interesting view of memory and how to manage it in C and C++. Again, memory is such an important concept that it is valuable for programers using other languages.

Other Links

Page for Null Pointers in the C Faq, explains what a NULL pointer is and how it is represented in several architectures.

Class notes on null pointers give a brief introduction to how to use null pointers.

Post on avoid null references on Lambda Ultimate provides some information on how these problems are avoided in Eiffel.

A paper mentioned on the previous page, about how to implement safety mechanisms against null dereferencing in Eiffel.

Using Gmail as a Notebook

Gmail is a great email reader that has been used by millions of people. Among all the software released by Google, few titles have reached so wide adoption.

The nice thing about Gmail is that it is so easy to use. So much so that it ends up being employed for more than it was originally designed.

For example, I know people that use Gmail as a to-do list. They simply send messages to themselves with a notice of something that needs to be done. Then, the message can be moved either to a special folder or left in the inbox, as a reminder of what needs to be done.

Some others use Gmail as a file repository. You can use up to seven GB of space in a Gmail account (the free ones, but you can always buy more space if you want). Thus, you can just send yourself files that you want to store, and move them into a particular folder.

Simple Notebook

Another use case that I have experimented with in the last few months is creating notes as message drafts. The idea is simple but effective. Gmail creates a draft message that is saved in regular intervals. You can also save the message manually if you want, using the save button in the top bar.

If you leave gmail before a message is completed, the content will be saved under the “drafts” label, so you can retrieve it later as needed.

When I want to create a note that can be edited later, I just write it as a new message. To avoid sending the note to a wrong address, you should remember not to add any destination on the “to” field.

Without a destination address, Gmail will never be able to send the message. This way, you can modify the content of the draft, and save it as if it were an independent file.

The only possible problem you might have with this scheme is that, if you delete the content of the message you’re working on, it cannot be retrieved later — there is no “deleted drafts” tag in Gmail.

A possible solution to avoid accidental deletion is to send the file to yourself regularly, effectively creating a copy of the file that will be stored indefinitely.

Other Links

Quick explanation of How to use Gmail as a file server

An ad-on for Firefox that can be used to transfer files to Gmail

A blog post about turning Gmail into a storage tool

Another blog post on using Gmail as storage

How is Your Software Designed?

Designing software is arguably the most import part of the development process, because it provides the foundation of what your resulting application will look like. During the design, a software creator can determine the best requirements for what needs to be built. The designer will be able to determine the best programming language and environment, as well as the general functions of the resulting application.

All this looks good, with the exception that it is not true. It is rare the case when software designers have the opportunity to determine all these parameters before the software development starts. Usually, a software designer has to start making a compromise by using the existing languages, machines, and related software.

Unprofessional Design

This is a sad state of things, because designing software should be left for professionals. Despite this, many believe that designing an application can be left to anyone, even to people without any experience in software development. This is the case, for example, when a buyer takes to himself the responsibility of designing how an application will look and work.

In commercial software houses, also known as independent software vendors, there is a strong push for the development of customized solutions. What this means is that developers will talk to clients and create software that can satisfy their particular needs.

Usually the conversation goes like this: the client wants to solve a general problem, such as inventory control. In order to do this, the client will pay for development, but they will also request a number of very specific features. For example, they will usually make requests about how the graphical interface will look like, or about the sequence of steps that the application will present to its users.

Imagine if we did this with architecture projects? A client would hire an architect and request a new project for a brand new building. However, for the sake of “usability”, the client would start to make all types of requests, such as “put the door on the left side of the building”, or “make windows that are a least 4 feet high”, followed by “put the main hall close to the meeting room”.

After a few dozen of these requests are made, the poor architect has nothing to do other than manage a bad design overall, which will most certainly compromise the original vision for the building.

Software and Architecture

Sure, architecture also has imposed limitations, but we cannot expect that clients will know the best architectural solutions for a building. On the other hand, common people feel that they are entitled to make requests on software design, especially when they are the ones paying for the project. For example, managers think they know what a software needs to do, even though they will not be the ones using it in most cases.

All this shows that there is a great weakness in software development per contract, where a client can impose restrictions and particular requests on how the software should work. It makes it very hard to come up with a solution that considers the core of the problem. This is another reason why custom made software is rarely good. It comes with so many attached strings that, at the end, it defeats its own purpose.