views:

1244

answers:

17

Why would a language NOT use Short-circuit evaluation? Are there any benefits of not using it?

I see that it could lead to some performances issues... is that true? Why?


Related question : Benefits of using short-circuit evaluation

+3  A: 

If you wanted the right hand side to be evaluated:

if( x < 13 | ++y > 10 )
    printf("do something\n");

Perhaps you wanted y to be incremented whether or not x < 13. A good argument against doing this, however, is that creating conditions without side effects is usually better programming practice.

superjoe30
I don't see a boolean expression in that code
Carson Myers
@Carson - The condition is in the pipe (|) which is designed as a bitwise 'or' operator with no short-circuiting. It's usually used for things like boolean math but it can be used in conditional statements as well. The circumstances in which you'd want to do this are rare, but you do at least have the option.
Steve Wortham
A: 

I don't know about any performance issues, but one possible argumentation to avoid it (or at least excessive use of it) is that it may confuse other developers.

Joonas Pulakka
+1  A: 

The Ada programming language supported both boolean operators that did not short circuit (AND, OR), to allow a compiler to optimize and possibly parallelize the constructs, and operators with explicit request for short circuit (AND THEN, OR ELSE) when that's what the programmer desires. The downside to such a dual-pronged approach is to make the language a bit more complex (1000 design decisions taken in the same "let's do both!" vein will make a programming language a LOT more complex overall;-).

Alex Martelli
-1 for talking about Ada in the past sense. The old gal's not dead yet
Pete Kirkham
True. However Ada generally errs on the side of simplicity and leaving decisions up to the compiler, so it had some room to spare in this direction. The language has fewer keywords than C++, and its entire BNF syntax fits on about 6 pages. A lot of that is to support things that C++ doesn't have, like specifically layout the exact location and offset of every record field, or specify threading and synchronization. If you were to stick to a C or C++-like subset of the language, it is actually *much* simpler than either.
T.E.D.
+5  A: 

One benefit I can think of is that some operations might have side-effects that you might expect to happen.

Example:

if (true || someBooleanFunctionWithSideEffect()) {
    ...
}

But that's typically frowned upon.

Ben S
This is similar to superjoe30's answer (increment y each time). The argument against this is to run someBooleanFunctionWithSideEffect() and assign the result so you can later test it. doing so is much clearer and easier to read and understand what is happening
shufler
Yes, which is why I say that my example is frowned upon.
Ben S
unless you want `someBooleanFunctionWithSideEffect()` to only perform its side effect if the first operation was false.
Carson Myers
@Carson Myers: Then you should probably have another if block demonstrating that logic.
Ben S
+1  A: 

Because short-circuiting can change the behavior of an application IE:

if(!SomeMethodThatChangesState() || !SomeOtherMethodThatChangesState())
Spencer Ruport
And using short circuiting will help to get rid of these type of statements.
Cem Kalyoncu
+4  A: 

Ada does not have it by default. In order to get short-circut you have to use "and then" or "or else" instead of "and" or "or".

I believe the issue was that there are some circumstances where it actually slows things down. If the second condition is quick to calculate and the first condition is almost always true for "and" or false for "or", then the extra check-branch instruction is kind of a waste. However, I understand that with modern processors with branch predictors, this isn't so much the case.

I've heard objections that it can lead to unexpected behavior of the code in the case where the second test has side effects. IMHO it is only "unexpected" if you don't know your language very well, but some will argue this.

In case you are interested in what actual language designers have to say about this issue, here's an excerpt from the Ada 83 (original language) Rationale:

The operands of a boolean expression such as A and B can be evaluated in any order. Depending on the complexity of the term B, it may be more efficient (on some but not all machines) to evaluate B only when the term A has the value TRUE. This however is an optimization decision taken by the compiler and it would be incorrect to assume that this optimization is always done. In other situations we may want to express a conjunction of conditions where each condition should be evaluated (has meaning) only if the previous condition is satisfied. Both of these things may be done with short-circuit control forms ...

In Algol 60 one can achieve the effect of short-circuit evaluation only by use of conditional expressions, since complete evaluation is performed otherwise. This often leads to constructs that are tedious to follow...

Several languages do not define how boolean conditions are to be evaluated. As a consequence programs based on short-circuit evaluation will not be portable. This clearly illustrates the need to separate boolean operators from short-circuit control forms.

T.E.D.
VB uses the same concept, except that VB has AndAlso, and OrElse if you want short circuiting.
Kibbee
@Kibbee: Sorry but you are mistaken. You are confusing bit operations with logical operations and are probably using `Option Strict Off` which allows more lax type checking. Nonetheless, there’s a clean semantical distinction between the two operations and the bit operations were never meant for conditionals in VB.NET (if they were, they would still work with `Option Strict On` which they don’t).
Konrad Rudolph
@Konrad - I'm sure you know the And and Or operators in VB.NET were left as is for legacy purposes from older versions of VB. But they can still be used for conditional statements (albeit 99% of the time the short-circuiting logical operators are preferred). But your statement about Option Strict is incorrect. All Option Strict On does is prevent implicit conversion. As long as you're not doing that then the bitwise And and Or operators will indeed work for conditional statements.
Steve Wortham
T.E.D.
@Konrad, you can still use And or Or with Option Strict On. The very first line of the And Operator in the VB Language Reference is: "Performs a logical conjunction on two Boolean expressions, or a bitwise conjunction on two numeric expressions" It's an overload, and And is fine as long as you use booleans on either side and not numerics.
Richard Gadsden
@Richard Gadsden: Duh. I could have sworn that VB with `Option Strict` wouldn’t compile code such as `If 1 And 2 Then …` because that would require an implicit conversion from `Integer` to `Boolean`. I just tested, and (Mono at least) compiles that code. I’m filing a bug report now. Furthermore, using `And` in boolean context may be “fine” since it compiles, but it sure isn’t clean code (as opposed to its usage in VB6).
Konrad Rudolph
+4  A: 

Look at my example at On SQL Server boolean operator short-circuit which shows why a certain access path in SQL is more efficient if boolean short circuit is not used. My blog example it shows how actually relying on boolean short-circuit can break your code if you assume short-circuit in SQL, but if you read the reasoning why is SQL evaluating the right hand side first, you'll see that is correct and this result in a much improved access path.

Remus Rusanu
+2  A: 

The language Lustre does not use short-circuit evaluation. In if-then-elses, both then and else branches are evaluated at each tick, and one is considered the result of the conditional depending on the evaluation of the condition.

The reason is that this language, and other synchronous dataflow languages, have a concise syntax to speak of the past. Each branch needs to be computed so that the past of each is available if it becomes necessary in future cycles. The language is supposed to be functional, so that wouldn't matter, but you may call C functions from it (and perhaps notice they are called more often than you thought).

In Lustre, writing the equivalent of

if (y <> 0) then 100/y else 100

is a typical beginner mistake. The division by zero is not avoided, because the expression 100/y is evaluated even on cycles when y=0.

Pascal Cuoq
Interesting language. How would you avoid dividing by 0 then?
Bill
Probably the old-fashioned way: Nested ifs.
T.E.D.
@Bill The '/' is in fact a call to the division of C. One way to avoid the division by zero is to replace it by a call to a "safe" division function that tests for zero. The recommended way would be to use "sampling" to create a ("slower") stream that contains *only* the non-zero values of y.A better link for Lustre than the Wikipedia page that I gave is http://www-verimag.imag.fr/PEOPLE/Pascal.Raymond/edu/eng/lustre-a.pdf
Pascal Cuoq
Wouldn't it make sense to allow the short-circuiting operators in cases like this, and have the compiler use sampling? And how do you write a safe division function?
David Thornley
+21  A: 

Reasons NOT to use short-circuit evaluation:

  1. Because it will behave differently and produce different results if your functions, property Gets or operator methods have side-effects. And this may conflict with: A) Language Standards, B) previous versions of your language, or C) the default assumptions of your languages typical users. These are the reasons that VB has for not short-circuiting.

  2. Because you may want the complier to have the freedom you reorder and prune expressions, operators and sub-expressions as it sees fit, rather than in the order that the user typed them in. These are the reasons that SQL has for not short-circuiting (or at least not in the way that most developers coming to SQL think it would). Thus SQL (and some other languages) may short-circuit, but only if it decides to and not necessarily in the order that you implicitly specified.

I am assuming here that you are asking about "automatic, implicit order-specific short-circuiting", which is what most developers expect from C,C++,C#,Java, etc. Both VB and SQL have ways to explicitly force order-specific short-circuiting. However, usually when people ask this question it's a DWIM* question, that is they mean "why doesn't it Do What I Want?", as in, automatically short-circuit in the order that I wrote it.

*- DWIM = "Do What I Meant"

RBarryYoung
+1: VB was the first programming language I learned (besides web-based stuff) and because it didn't have short-circuiting, I had to learn what it was the hard way when I learned C.
Carson Myers
+1. Although I suppose on point 2, the compiler could be allowed to short-circuit either part of the expression depending on its preferences - it doesn't have to do it in the order the user typed them in.
MarkJ
+1 for mentioning SQL.
Daniel Pryden
@MarkJ: No, it cannot. Think of the Java expression `(thing == null || thing.getField() == 1)`.
Dirk
MarkJ: yes, for #2, the language could (and does in SQL's case) selectively short-circuit, but "short-circuiting" question by developers are *always* of the nature of "Why doesn't WHERE IsNumeric(FooStr) AND CAST(FooStr As Numeric) > 0..., work right?" That is, "why doesn't it short-circuit the way that I told it to?"
RBarryYoung
Konrad Rudolph
I think the better question is:Why doesn't a language use short-circuit evaluation as a default? For VB, I end up ALWAYS using AndAlso and (AndAlso?) OrElse, having to consciously omit the Also|Else when I want to avoid short-circuit
Joey
Konrad: VB does not have implicit or default short-circuiting, which is what most people mean when they ask this question. You are right about the bit-wise operators vs. logical, I had forgotten about that. Nonetheless, it does not change my answer, because on conditional-tests, the resulting bit-mask is coerced into a logical-value for the test anyway (semantically) and because of that, short-circuiting could STILL be used validly (though perhaps more limited in its application).
RBarryYoung
I really like that VB gives the choice to the programmer about whether or not to short circuit.
Kibbee
On a side note, isn't calling functions/methods that change state within a conditional itself a bad idea?
MAK
MAK: the vast majority of C/C++/C#/Java code in the world is written like this, because the style is to return the status results of operational routines as function return values. In this way, sequential OR's in C# become the equivalent of nested IF's in VB.
RBarryYoung
And of course, that only works if implicit short-circuiting is a given.
RBarryYoung
Konrad Rudolph
Konrad Rudolph
There's a whole conversation here about VB.NET that calls it VB. VB6 / VBA / VBScript don't have AndAlso / OrElse operators in the first place. I also don't agree that And / Or are bitwise operators; they're overloaded as both bitwise and logical depending on the parameters.
Richard Gadsden
A: 

There are already great responses about the side-effect issue, but I didn't see anything about the performance aspect of the question.

If you do not allow short-circuit evaluation, the performance issue is that both sides must be evaluated even though it will not change the outcome. This is usually a non-issue, but may become relevant under one of these two circumstances:

  • The code is in an inner loop that is called very frequently
  • There is a high cost associated with evaluating the expressions (perhaps IO or an expensive computation)
Eric J.
You must have missed my answer then. In fact, there are some circumstances where it could be faster to *not* use short-circuit. That is why Ada gives you both forms.
T.E.D.
Sorry there were a lot of answers already :-)
Eric J.
A: 

The short-circuit evaluation automatically provides conditional evaluation of a part of the expression.

The main advantage is that it simplifies the expression.

The performance could be improved but you could also observe a penalty for very simple expressions.

Another consequence is that side effects of the evaluation of the expression could be affected.

In general, relying on side-effect is not a good practice, but in some specific context, it could be the preferred solution.

Chris
+2  A: 

Not that I think this is what's going on in any language now, but it would be rather interesting to feed both sides of an operation to different threads. Most operands could be pre-determined not to interfere with each other, so they would be good candidates for handing off to different CPUs.

This kins of thing matters on highly parallel CPUs that tend to evaluate multiple branches and choose one.

Hey, it's a bit of a stretch but you asked "Why would a language"... not "Why does a language".

Bill K
Even if the language doesn't do it in multiple threads a program compiled to machine code might benefit from not having short circuit. This is because processors pipeline the operations they are doing and if they know then need to evaluate both sides it can pipeline the whole thing without having to account for rollback. However, if there is short circuit evaluation then it adds another branch in the code that either stops the pipeline or the processor has to account for rollback.
tster
A: 

VB6 doesn't use short-circuit evaluation, I don't know if newer versions do, but I doubt it. I believe this is just because older versions didn't either, and because most of the people who used VB6 wouldn't expect that to happen, and it would lead to confusion.

This is just one of the things that made it extremely hard for me to get out of being a noob VB programmer who wrote spaghetti code, and get on with my journey to be a real programmer.

Carson Myers
Yes, newer versions *definitely* do use short-circuiting (`AndAlso`, `OrElse`, which is *good* VB parlance). VB1–6 was just handicapped that way.
Konrad Rudolph
so it's like Ada in that it has an extra, short-circuiting keyword? I'll have to remember that in case I start using VB again
Carson Myers
+4  A: 

I'd say 99 times out of 100 I would prefer the short-circuiting operators for performance.

But there are two big reasons I've found where I won't use them. (By the way, my examples are in C where && and || are short-circuiting and & and | are not.)

1.) When you want to call two or more functions in an if statement regardless of the value returned by the first.

if (isABC() || isXYZ()) // short-circuiting logical operator
    //do stuff;

In that case isXYZ() is only called if isABC() returns false. But you may want isXYZ() to be called no matter what.

So instead you do this:

if (isABC() | isXYZ()) // non-short-circuiting bitwise operator
    //do stuff;

2.) When you're performing boolean math with integers.

myNumber = i && 8; // short-circuiting logical operator

is not necessarily the same as:

myNumber = i & 8; // non-short-circuiting bitwise operator

In this situation you can actually get different results because the short-circuiting operator won't necessarily evaluate the entire expression. And that makes it basically useless for boolean math. So in this case I'd use the non-short-circuiting (bitwise) operators instead.

Like I was hinting at, these two scenarios really are rare for me. But you can see there are real programming reasons for both types of operators. And luckily most of the popular languages today have both. Even VB.NET has the AndAlso and OrElse short-circuiting operators. If a language today doesn't have both I'd say it's behind the times and really limits the programmer.

Steve Wortham
If you want to evaluate the second expression, **make it explicit**! Do *not* use arcane code like the above, it’s extremely hard to read and thus prone to misunderstanding. Likewise for Boolean math.
Konrad Rudolph
I see what you're getting at now. I wrote it the way I did to make it easier to illustrate the difference.
Steve Wortham
Heh, that's funny. I've known C since the mid 80's, and it had never occurred to me to use the bitwise operators to get the effect of a non-short circuit boolean check. It's kinda dangerous, as the bitwise and won't work the way you want if the two values are non-zero but happen to have different bits set. Still, its an interesting hack. The only safe way to do it in C is to save both calculations into temporaries and check those with the boolean operator.
T.E.D.
While "if (abc() | xyz())" is usually the same as "if (abc() || xyz())" except for the evaluation of xyz(), remember that "if (abc()
David Thornley
@David - I was imagining that abc() and xyz() would both return boolean values. Your point is well taken though. It's what I was trying to illustrate in #2 (the whole boolean math thing).
Steve Wortham
I just updated my examples to hopefully make them a little more clear.
Steve Wortham
+1  A: 

As a stretch:

If you wanted a language to be super secure (at the cost of awesomeness), you would remove short circuit eval. When something 'secure' takes a variable amount of time to happen, a Timing Attack could be used to mess with it. Short circuit eval results in things taking different times to execute, hence poking the hole for the attack. In this case, not even allowing short circuit eval would hopefully help write more secure algorithms (wrt timing attacks anyway).

Daniel Huckstep
+4  A: 

Bill has alluded to a valid reason not to use short-circuiting but to spell it in more detail: highly parallel architectures sometimes have problem with branching control paths.

Take NVIDIA’s CUDA architecture for example. The graphics chips use an SIMT architecture which means that the same code is executed on many parallel threads. However, this only works if all threads take the same conditional branch every time. If different threads take different code paths, evaluation is serialized – which means that the advantage of parallelization is lost, because some of the threads have to wait while others execute the alternative code branch.

Short-circuiting actually involves branching the code so short-circuit operations may be harmful on SIMT architectures like CUDA.

– But like Bill said, that’s a hardware consideration. As far as languages go, I’d answer your question with a resounding no: preventing short-circuiting does not make sense.

Konrad Rudolph
+1  A: 

I'd say it's valid for readability issues; if someone takes advantage of short circuit evaluation in a not fully obvious way, it can be hard for a maintainer to look at the same code and understand the logic.

If memory serves, erlang provides two constructs, standard and/or, then andalso/orelse . This clarifies intend that 'yes, I know this is short circuiting, and you should too', where as at other points the intent needs to be derived from code.

As an example, say a maintainer comes across these lines:

if(user.inDatabase() || user.insertInDatabase()) 
    user.DoCoolStuff();

It takes a few seconds to recognize that the intent is "if the user isn't in the Database, insert him/her/it; if that works do cool stuff".

As others have pointed out, this is really only relevant when doing things with side effects.

CoderTao
You can write obscure code with any constructs. Trust me on this.
David Thornley
I don't doubt it, but the point of the language is to try and make it ever so slightly more difficult to be unclear.
CoderTao
Well... most languages at least. INTERCAL is still a special case.
CoderTao