Why would a language NOT use Short-circuit evaluation?
Asked Answered
C

18

39

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

Colleague answered 18/9, 2009 at 17:28 Comment(13)
What language doesn't that you have in mind? I can't think of any that don't use short-circuit evaluation.Innumerable
+1 for me wondering the same thing. I wonder why there would be performance issues especially if all the possible expressions are possibly not being evaluated.Resupinate
@Ben S: SQL. The query optimizer decides whether or not to evaluate AND's and OR'sEnedina
@ben s:I don't have a specific language in mind. @buggabill: There is a beginning of explanation for the perf issue on the wikipedia page but it doesn't satisfy me :)Colleague
This is language dependent, PHP for instance never evaluates second argument if boolean operation is definitive from the first argument.Containment
I distinctly remember Lattice C having a command-line argument to force "Complete Boolean Eval"Susannsusanna
SAS does not do short circuit evaluationFeline
@marcgg: I see what you mean... =)Resupinate
VB6 doesn't use short-circuit evaluation.Annabellannabella
Standard-Pascal doesn't have short-circuit evaluation either. The (former) Borland guys added this as a compile-time optional feature somewhen around Turbo Pascal 5 or 6 IIRC.Salter
@ Ben S: Erlang has two sets of conditional operators: one that does short-circuit evaluation, and one that does not. The commonly-used and and or keywords do not do short-circuit evaluation (you have to use andalso and orelse to get short-circuiting behavior).Oud
Somewhat different as a language - but Standard SQL does not provide short-circuit evaluation operators (or, to be more precise, the normal AND, OR, NOT operators are not short-circuit operators; there may be short-circuit alternatives in the SQL dialects provided by some DBMS).Boatbill
@mipadi: Ah! that's where VB.Net got those awful operators from :-)Runkel
F
40

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 compiler to have the freedom to 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 "Do What I Meant" 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.

Faunia answered 18/9, 2009 at 17:36 Comment(14)
+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.Irrigation
+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.Blacktail
@MarkJ: No, it cannot. Think of the Java expression (thing == null || thing.getField() == 1).Salter
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?"Faunia
Sorry, that’s patent nonsense. VB does have short-circuiting. The reason that And and Or don’t short-circuit is that they aren’t boolean operations at all. Rather, they’re bit operations (equivalent to C’s & and |).Disadvantage
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-circuitGalarza
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).Faunia
I really like that VB gives the choice to the programmer about whether or not to short circuit.Rottweiler
On a side note, isn't calling functions/methods that change state within a conditional itself a bad idea?Cellobiose
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.Faunia
And of course, that only works if implicit short-circuiting is a given.Faunia
Barry: There’s a misunderstanding here. VB, by default (and implicit, whatever you mean by that), does short-circuiting. Full stop. The misunderstanding comes about because VB uses other keywords for these operations and so you apparently assume that it’s not the default operation. Also, (at least with Option Strict On which is the only meaningful setting in VB) there is absolutely no implicit coercion from bit-masks to boolean values. And and AndAlso are (almost) completely unrelated operations, just like && and & – in fact, they’re direct equivalents. …Disadvantage
(cont’d) Saying that VB doesn’t “have impliciy implicit or default short-circuiting” is like saying that C# doesn’t have it and in either case, it’s just plain wrong. If you use And in a conditional statement in VB you are committing a semantical mistake just as if you were using & in a conditional statement in C#, and the compiler will issue an error accordingly. So Kibbee is wrong as well: VB doesn’t give you the choice in that matter either (unless you were referring to Option Strict). There’s a clear semantical distinction between logical operations and bit operations.Disadvantage
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.Booster
I
7

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.

Innumerable answered 18/9, 2009 at 17:35 Comment(5)
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 happeningConsolidate
Yes, which is why I say that my example is frowned upon.Innumerable
unless you want someBooleanFunctionWithSideEffect() to only perform its side effect if the first operation was false.Irrigation
@Carson Myers: Then you should probably have another if block demonstrating that logic.Innumerable
@CarsonMyers that wouldn't work, sure it'll perform the side effect when the first operation is false, but it'll also do it when it's true as well. so it's not only performing it when the first operation is false.Babylonian
E
5

Ada does not do it by default. In order to force short-circuit evaluation, you have to use and then or or else instead of and or or.

The issue is 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. Another issue is that the compiler may happen to know that the second half is cheaper or likely to fail, and may want to reorder the check accordingly (which it couldn't do if short-circuit behavior is defined).

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.

Electronics answered 18/9, 2009 at 17:35 Comment(6)
VB uses the same concept, except that VB has AndAlso, and OrElse if you want short circuiting.Rottweiler
@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).Disadvantage
@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.Superdreadnought
I don't know about VB, but in languages I do know a bitwise and is a very different animal than a boolean and. For example, in C '2 && 1' is true, while '2 & 1' is false (none of the same bits are set in the two operands).Electronics
@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.Booster
@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).Disadvantage
A
4

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.

Arlinearlington answered 18/9, 2009 at 17:36 Comment(0)
S
4

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.

Superdreadnought answered 18/9, 2009 at 18:7 Comment(6)
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.Disadvantage
I see what you're getting at now. I wrote it the way I did to make it easier to illustrate the difference.Superdreadnought
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.Electronics
While "if (abc() | xyz())" is usually the same as "if (abc() || xyz())" except for the evaluation of xyz(), remember that "if (abc() & xyz())" is NOT the same as "if (abc() && xyz())" - consider what happens if abc() returns 1 and xyz() returns 2. That's why I'd strongly advise not writing a boolean with "|"; it means you're likely to do it with "&".Niveous
@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).Superdreadnought
I just updated my examples to hopefully make them a little more clear.Superdreadnought
D
4

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.

Disadvantage answered 18/9, 2009 at 18:22 Comment(0)
A
3

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.

Adjure answered 18/9, 2009 at 17:33 Comment(1)
@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.Superdreadnought
S
3

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;-).

Scouting answered 18/9, 2009 at 17:34 Comment(2)
-1 for talking about Ada in the past sense. The old gal's not dead yetJordonjorey
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.Electronics
U
3

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).

Uniformed answered 18/9, 2009 at 18:21 Comment(0)
R
2

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.

Rommel answered 18/9, 2009 at 17:36 Comment(4)
Interesting language. How would you avoid dividing by 0 then?Melbourne
Probably the old-fashioned way: Nested ifs.Electronics
@Melbourne 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 www-verimag.imag.fr/PEOPLE/Pascal.Raymond/edu/eng/lustre-a.pdfRommel
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?Niveous
E
2

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".

Entertain answered 18/9, 2009 at 17:51 Comment(1)
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.Crab
G
1

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

if(!SomeMethodThatChangesState() || !SomeOtherMethodThatChangesState())
Gonna answered 18/9, 2009 at 17:35 Comment(1)
And using short circuiting will help to get rid of these type of statements.Containment
M
1

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.

Misgive answered 18/9, 2009 at 18:57 Comment(3)
You can write obscure code with any constructs. Trust me on this.Niveous
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.Misgive
Well... most languages at least. INTERCAL is still a special case.Misgive
P
0

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.

Peregrinate answered 18/9, 2009 at 17:34 Comment(0)
J
0

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)
Jonson answered 18/9, 2009 at 17:45 Comment(1)
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.Electronics
H
0

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.

Higginson answered 18/9, 2009 at 17:46 Comment(0)
I
0

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.

Irrigation answered 18/9, 2009 at 17:52 Comment(2)
Yes, newer versions definitely do use short-circuiting (AndAlso, OrElse, which is good VB parlance). VB1–6 was just handicapped that way.Disadvantage
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 againIrrigation
M
0

Many answers have talked about side-effects. Here's a Python example without side-effects in which (in my opinion) short-circuiting improves readability.

for i in range(len(myarray)):
  if myarray[i]>5 or (i>0 and myarray[i-1]>5):
    print "At index",i,"either arr[i] or arr[i-1] is big"

The short-circuit ensures we don't try to access myarray[-1], which would raise an exception since Python arrays start at 0. The code could of course be written without short-circuits, e.g.

for i in range(len(myarray)):
  if myarray[i]<=5: continue
  if i==0: continue
  if myarray[i-1]<=5: continue
  print "At index",i,...

but I think the short-circuit version is more readable.

Meeting answered 24/2, 2012 at 6:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.