How Developers Are Like Pigeons

In one of his most well know experiments,  B. F. Skinner – the  founder of branch of psychology  known as Radical Behaviorism,   set an automated mechanism  to  give pigeons food  pellets on every predefined constant interval.   Nothing the pigeons  did had anything to do with whether or not they will get the food.  Yet the pigeons appeared to associate getting it with  whatever they were doing at the time.   One of the birds walked in circles  around the cage,  others repeatedly moved their body in a particular way  and some birds did nothing.

No matter what a pigeon did, at the end (of the time interval) it was rewarded with a delicious pellet of food.  Providing further proof that whatever it was doing worked yet again which lead in turn, to a repetition of  the action during the next waiting period.

This simple experiment tried to explain how people come to associate events in their life to  unrelated behaviors and believes also known as superstitions.

While we  developers do not work for food pellets (unless you consider pizza)  we are known to be sensitive to our software not working as expected.  Misbehaving software leads to all kinds of unpleasantness ranging  from uncomfortable embarrassment,  through a never ending all-nighters and all the way to  billions of dollars in  losses.   In an attempt to avoid these uncomfortable situations, and similar to Skinner’s pigeons,  many of us developed a few rituals in our code serving no real purpose other than  warding off imaginary code failures.

here are a few examples I run into :

1. Checking for  a null when calling a new operator  I am sure everyone has seen something similar to this code snip:

  	myClass* mc = new myClass();
  	if (mc == NULL)
  	{
	  Log("Could not allocated memory for  myClase");
  	}

With any modern C++  compiler, the if statement will  never get executed.  The  new operator’s  default behavior is throwing an exception when failing to create the object.    Years ago this kind of code made sense in C code when  as C dynamic allocation function  malloc  returned  a 0 (NULL) on failure. Later in 1998 ,  due to one of many  noncompliances with the standard ,  Microsoft’s Visual Studio 6  C++  compiler, generated code which returned a null by default instead of throwing and exception.  It was fixed in the next version of VS –  15 years ago!  My best guess is that new developer notices this pattern in old code and end up copying it to their own new code “just to be on the safe side” copying it to their own new code and unwittingly continuing the chain.
It is, in fact, possible to have the new operator return a null by calling

myClass* pMc = new(std::nothrow) myClass();

or, by overloading the new operator,  but usually this is not the case.

2. Using NULL or even worse – 0  instead of nullptr:   the nullptr keyword was introduced in C++11 , ending years of having to define  the line:

#define NULL 0

In a header file visible to all  source files.  Yet, more than 5 years later people  keep using a syntax similar to the if  statement in  the previous example. Just in case the compiler didn’t get the memo   that nullptr is an invalid pointer evaluating to  0.

3. Inilizieing an std:string to an empty string:

std::string myString = “”

The of std::string’s  default constructor,  guarantees  the newly created string is empty. Assigning it an empty string literal has no practical value.

3.  having an else clause after a throw

if (myString.empty())
{
	throw myException("Fatal : Empty string")
}
else
{
	myString = myString
}

If the string is indeed null  triggering  the throw statement,  program execution path will be redirected to the closes suitable catch clause skipping the code following the if . The only way the else code will ever get executed is if somehow the throw keyword  is ignored by the compiler, but then  with the compiler producing unpredictable code wouldn’t an empty string be least of our worries ?

Conclusion

Superstitions code may seem harmless at first glance,  but it has a hidden price in code readability and possibly in performance. This kind of code is often difficult to root out as over time we no longer question its validity. Doing  code review and/or paying close attention to the compiler or static analyzer’s  warning  is the best way to clean up these parasitic code segments.

Leave a comment with other examples of superstitions code