Вселенная Кудзу

«Программирование - искусство, воюющее со своими творцами»

Kudzu World  »  Articles  »  FaultyCircuits
English - Română - Русский - عربي

Did you know?

The kudzu plant can grow 7 feet (over 2 meters) per week? Find out more about the amazing kudzu plant.




Using PayPal?
Read this


Short Circuits or Faulty Circuits?

Short circuiting in software development is a common practice and often propagated and accepted as a good practice because of this. However common practice is not always the best practice, and in this article I will demonstrate why I believe short circuiting is not a good practice and why it should not be used. As with any such debate, it is up to you to make the final decision based on the arguments as to whether it is a good practice for you and your team.

What is Short Circuiting?

The term short circuiting comes from electrical terminology:

n 1: electrical circuit is overloaded [syn: short] 2: when two points that have a potential difference come into contact the circuit is said to be shorted.

When this situation occurs in an electrical circuit, the wires or the circuit burn out and a fire often occurs if no safety mechanisms such as a fuse or breaker are in place. Its ironic that although through different means, similar effects are often caused in source code (Access violations, errors) are caused by use of the practice that shares the same name.

Compiler Short Circuiting

When we talk about short circuiting in terms of software it refers to a compiler optimization that most compilers support known as "Short circuit boolean evaluation". Short circuiting causes boolean comparisons to be evaluated only as far as needed to determine the outcome. Such an optimization can lead to significant performance gains.

Consider the following example:

a and b and c and d

Such a boolean expression can be used in if statements, loops or other. Each expression (a, b, c, d) is any type of evaluation that results in a boolean result such as I = 4 (Pascal), I == 4 (C, C++, Java). In the above boolean equation, if a is false, it does not matter what the results of b, c, or d are. That is the compiler can know the outcome simply by evaluating a, and save time by stopping evaluation as soon as it knows the definitive outcome.

Short Circuit Reliance

Short circuit reliance is the coding practice of relying on the fact that the compiler will short circuit a statement. That is given the following expression:

a and b and c and d

b is dependent on a, c on b, and d on c. If a is false, b must not be evaluated else an access violation or other program error will occur as the evaluation is not even valid.

Optimization is Good

The practice of a compiler performing short circuiting is a very good one, and should be used in most cases as it provides tangible performance benefits with minimal side effects. However the practice of short circuit reliance is a poor one, and that is the focus of this article.

Reason: Not Portable

Some compilers and langauges to not support short circuiting. Translation of logic into such languages will lead to bugs either in direct translation or expansion of the logic.

Reason: Ordering

The ordering of the expression is very important which makes it different from a true boolean formula. If any boolean optimization or rearranging is performed, a bug will very likely occur. Code rarely reads as simple as:

a and b and c and d

Because of this it is not always obvious that a statement relies on short circuiting and any reordering caused by later changes or optimizations will very likely introduce a bug.

Reason: Order of Operations

Because functions must be evaluated in a specific order, that exact order must be known before hand by the developer. Simple expressions are easy to predict, however with the introduction of order of operations, and explicit ordering (parentheses) the exact order of function calls is not the standard left to rigtht. Predicting that dependent evaluations will be called in the proper order is absolutely necessary with short circuits, and not always an easy or reliable task.

Reason: Common Mistakes

Many C++ texts list short circuit boolean evaluation mistakes in the top 10 most common mistakes that cause bugs.

Reason: It's on, it's off

In some circles full evaluation reliance was practiced. That is it was relied on the fact that full evaluation occurred and that any functions in an expression would be evaluated. Consider:

var
  I: Integer;

function Count: boolean;
begin
  I := I + 1;
end;

x := True;
while x and (Count < 10) do begin
  if <some condition> then begin
    x := False;
  end;
end;

Such a function allows x to be used to prematurely exit the loop. However if <some condition> never becomes true, the function Count will never be called if short circuiting is in effect. While this used to be fairly common practice, programmers have learned that short circuits cause bugs to occur in such full evaluation reliance conditions. Developers today consider full evaluation reliance a bad practice because short circuiting might exist. If one reliance is considered bad, the inverse (Short circuit reliance) should be considered a poor practice as well.

Objections

Any good debate about a topic should not only include reasons for or against, but should also address common objections or common beliefs. The next sections will contain common objections used to justify short circuit reliance and why they either do not apply, or are false statements.

Objection: It is common practice

Many people ride without seat belts, jump off bridges, smoke, drink, and many other unhealthy things. Common practice does not make best practice.

Objection: Its an elegant tool

Any time I hear the phrase "It's an elegant solution", I become really worried. This is some sort of code word for "Its complicated, short on code, and very brittle". "Elegant" reminds me of C++ code I've seen that looked like ancient Egyptian because a programmer wrote it "elegantly" and used operator overloading to remap all kinds of operators. Other uses of "elegant" remind me of developers describing self modifying code.

Simply applying a disconnected adjective to a practice is not a valid argument.

Objection: It saves space

A common objection is that it saves space.

if a and b then begin
  ..
end;

is in fact shorter than:

if a then begin
  if b then begin
    ..
  end;
end;

Compactness of code is nice, but only when it does not have a side effect of increasing the likeliness of bugs, and does not make the code more difficult to understand the intent. Simple short circuiting practices may be relatively easy to spot, but more complex ones certainly will not be. Simple short circuits also have a tendency to grow into complex ones over time.

Furthermore these are normally the same developers who will write:

if x then
begin
  ..
end
else
begin
  ..
end;

instead of:

if x then begin
  ..
end else begin
  ..
end;

I am not arguing that one construct is better than the other in this article. In general it is purely personal preference. However, it turns the argument that "it saves space" into a paper tiger.

C++ also allows code to be written in a very compact manner, but at serious trade offs to readability. Very few C++ programmers use every option available to them to produce fewer source code lines as the source code would be very difficult to maintain.

Objection: It is more efficient

There are several points regarding this objection:

  1. It is when compared to a full evaluation. However when compared to a split if / logic statement, the final execution will in most cases be no different.
  2. The compiler optimization can still be used.
  3. Programmers often optimize the wrong sections based on gut feelings when in fact much bigger bottlenecks exist in other parts of the program and will hide any optimizations made by the developer.
  4. In half the cases there is not speed improvement. In the other half the savings is one machine cycle in most constructions. Is it really worth saving 1 machine cycle of execution time in a trade off of several hours of debugging later? Do you really think 1 machine cycle in the context of the routine will make any measurable or quantifiable difference?

Objection: I do not like it

Emotional arguments have no place in technical debates. In the past I have often over a period of time come to see that certain practices that I had used for years were not the best technical decisions. After coming the decision to change them, the new practices often "grated" me for weeks or even months afterward. However such changes have since increased the reliability of my code, and reduced the number of bugs.

Summary

Short circuit reliance is a brittle practice and will lead to more bugs than when used, than in code which does not use it. Using short circuit reliance offers little benefit, but has large liabilities. On the other hand, the drawbacks of not using short circuit reliance are minimal, mostly cosmetic in nature, and increase code reliability.

Typically the first use of a short circuit is reliable. However succesive changes often cause the short circuit to become not readily noticable, and thus further changes cause errors. As a team leader of many teams over the years,  I have spent a fair amount of debugging time on errors that were caused by this very practice of short circuit reliance, which is a slippery slope.

I have also noticed that while short circuit reliance may be less problematic with code developed by a single developer, it is much more problematic in team developed code. This may be because a single developer knows exactly his (or her) own style, and remembers each sections use of short circuiting semantics.

Feedback

I realize that this is a religious issue and that some developers are so emotional about this topic that no matter of logic will ever cause them to reconsider. I have spent many hours in technical debate about this issue. However since the release of this article, I have also heard from many developers who say that this article has enlightened them and they have altered their habits.

Most developers who still retain short circuit reliance as a practice after reading this article still cite "it saves space", while using separate lines for each begin, and every end. In the end, for most programmers its an old habit, and old habits die very hard. The first step in recovery, is admission. :)