12

To be a bit more clear, I'll state that I've spent lots of time with different languages. But until now it's been either it'll use it all the time or it doesn't support it at all.

Now work has me starting on projects that require VB.net and I see it provides it both ways in terms of AND and ANDALSO. The first one does not short circuit, and the 2nd one does.

So this leads me to wonder why? As having it setup like this seems to imply that it would come up quite often that one would want to switch modes. But I can't think of any situations where it would be a bad thing to use Short Circuit.

I know this could very well get into more of an option thing, so if I need to put this at some place else just tell me where.

Though I'm hoping there is at least an official answer, as to why having both options would be better then always doing Short Circuit, when it's available.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
Kit Ramos
  • 231
  • 2
  • 6
  • 2
    Quite a duplicate on SO: [Why would a language NOT use Short-circuit evaluation?](https://stackoverflow.com/questions/1445867/why-would-a-language-not-use-short-circuit-evaluation) – Doc Brown May 30 '18 at 22:19
  • 1
    See also: https://softwareengineering.stackexchange.com/questions/246549/why-and-is-needed-when-there-is-andalso – Doc Brown May 30 '18 at 22:24

5 Answers5

20

Apparently, your question is not about short-circuiting being good or bad in general, but about why VB.NET provides operators with and and without it. With this in mind, the answer to

when is short-circuit evaluation bad?

is simply: when it violates backwards compatibility.

Ok, now you can say VB.NET is not very backwards compatible to old VB6 or VBA, however at least certain parts of the language are. Microsoft's decision of keeping the old AND and OR semantics (without short-circuiting) made a huge category of errors less likely to occur when when porting old VB programs to VB.NET.

On the other hand, VB.NET language designers probably shared your opinion about short-circuiting being a good thing. When I remember correctly, the first VB.NET pre-release versions provided AND or OR operators with short-circuiting, but the developer feedback must have been so bad MS withdraw this decision before VB.NET 1.0 appeared. So the designers decided to implemented it in terms of new keywords ANDALSO and ORELSE as a trade-off between backwards compatibility and usefulness.

IMHO this was a good decision. I had to port several older programs in the last decade, and not having to make a heavy impact analysis for every logic expression including AND and/or OR (pun intended) made that task a lot easier and more economic. On the other hand, whenever I have to write a new logical expression in VB.NET, my default choice for the operators are the short-circuit forms, that is what I am used to from C, C++, C# etc, and it allows me to write several idioms in more concise form (even if ANDALSO needs 4 characters more to type).

If you are not convinced, I recommend to read Joel Spolsky's great article about Martian Headsets, which is about why early design decisions in software development cannot be easily revoked after the component or language or API in stake has reached a user base of a certain size.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
  • Ok, this qualifies as a rant and the link to Martian Headsets doesn't seem to be related at all. – jwdonahue May 30 '18 at 20:26
  • 7
    @jwdonahue: I have no idea why you think this is a rant, quite the opposite. And the article about Martian Headsets is about why some design decisions in software development made several decades ago cannot be easily revoked after the component or language or API in stake has reached a user base of a certain size. Isn't the analogy really so hard to grasp? VB6 was *very* popular in the past, and I am sure still hundred thousands of companies in the world have mission critical apps running in VB6 or VBA. – Doc Brown May 30 '18 at 20:37
  • I don't quite see how the "Martian headests" article really fits. What's necessary to ensure interoperability between X's and Y's (e.g. nuts and bolts) is to have separate standards for X and Y, such that a worst-case nut will accommodate a slightly-worse-than-specified bolt, and vice versa. One should try to write the specs so as to avoid making nuts or bolts needlessly expensive, or having a needless amount of slop between nuts and bolts, but specifying both halves separately makes it possible to ensure interoperability far more reliably than trying to have one spec serve both sides. – supercat May 30 '18 at 23:22
  • 3
    @supercat: this is about having already trillions of nuts (or lines of VB6 code) existing and in use, and now the bolts (or in this case VB compiler) will be replaced by a newer generation. If the existing nuts fit only to non-metric bolts, it is not economic to make the newer bolts metric-system only. – Doc Brown May 31 '18 at 06:34
  • tl;dr: VB is a dialect of BASIC, a language dating from 1964, and in BASIC the `And` operation does not short circuit, neither does it in SQL (1974), nor FORTRAN (1956), nor Pascal (1970). – Ben May 31 '18 at 09:46
  • @DocBrown: If many varied nuts have been manufactured, and they're not all consistent, the proper remedy is generally not to try to specify a universal bolt, nor (as the C Standard does) specify bolts so loosely that almost any bolt that fits any nut is "conforming". Instead, one should attempt to standardize a classification of nuts and bolts such that knowing what class a particular nut and bolt fall into will let one predict whether they will work together, with a minimum of false positives, but as many true positives as can be achieved given that constraint. VB6 programs may be... – supercat May 31 '18 at 16:37
  • ...a type of "nut" [or many of them may be simply nuts], but the article's focus is on things that are poorly specified. So far as I can tell, the behavior of Boolean operators in VB6 has never been ambiguous. The comparison operators yield all-bits-false (i.e. 0) or all-bits-true (i.e. -1), and the Boolean operators compute both operands and compute a bitwise result. – supercat May 31 '18 at 16:41
5

Some terms in a logical expression can have side effects. It is sometimes necessary to ensure all side effects happen in the stated order, and none are skipped and it is the evaluation result that guides the logic:

if not (PushAirPlane(thrust) and TurnAirplane(vector)), SimulateCrash(severity)

In other cases, you don't want to evaluate any of the remaining terms if an earlier evaluation returns false.

if IsAirborne() and not (PushAirPlane(thrust) and TurnAirplane(vector)), SimulateCrash(severity)

Some will/have argued that relying on the short-circuit behavior in the second example is bad form, but that's getting into coding style and belief systems. There are many very good bits of code in the world that do rely on nearly every feature a language provides, and that's just the way it is.

VB's ANDALSO is crisp and seems to be an attempt to make the practice more acceptable.

As JimmyJames points out in his answer, there can be measurable performance implications around short-circuit evaluation. Languages that do not provide the mechanism, always evaluate every term of the expression, while those that do provide it, can generate extra branch statements. Either way, much depends on the number of processing steps required to evaluate each of the terms and also on compiler and CPU architectures. You would normally not care about such things until you have a measured bottleneck in the code and need to work out how to alleviate it. Any do or don't rules regarding allowing short-circuit evaluation in your code would have roughly equal chance of causing slower code and optimizing early can be a total waste of time, so always measure, then optimize.

jwdonahue
  • 222
  • 1
  • 6
  • This answer is factually correct. I don't understand why someone downvoted it. – JimmyJames May 30 '18 at 19:40
  • 4
    While factually correct, it's not a great design. – Robert Harvey May 30 '18 at 19:42
  • @JimmyJames I had a logic error in the second example until my last edit? – jwdonahue May 30 '18 at 19:42
  • @RobertHarvey, it's logically equivalent to `if IsAirBorne() if not...`, so it's exactly the same "design", it's just not always an accepted coding practice, but that gets us into the same territory as the one true bracing style. – jwdonahue May 30 '18 at 19:44
  • 1
    The one true brace style is far less problematic than avoiding short-circuiting because your methods cause actionable side-effects. – Robert Harvey May 30 '18 at 19:53
  • 2
    @RobertHarvey, I can't write a control system that does not have side effects and I cannot control the system correctly if I do not react to outcomes. In other words, get over it ;). – jwdonahue May 30 '18 at 20:25
  • 7
    No, but you can assign the results of those side-effecting functions to boolean variables, check those variables in your `if` condition and still short-circuit. I do agree that it is, in some ways, a stylistic distinction, but it does have the virtue of making things crystal-clear. – Robert Harvey May 30 '18 at 20:30
  • When speaking to folks who are fluent in a particular language, it's perfectly okay to use "big words" and nuance. The same is true of programming languages. Some need training wheels to protect them from falls, but they probably shouldn't be writing control systems anyway. Some people prefer the math and others need an ordered list of instructions. I personally prefer the short, self documenting one liners, over the alternative, but even then, only when it's not too complex to grok at a glance, otherwise I force my readers to absorb multiple blocks of distinct code. – jwdonahue May 30 '18 at 20:40
  • 3
    @jwdonahue It's okay to use "big words" if the risk of confusion is low. The risk of confusion and missing particular nuances of a block of code like this is *extremely* high and can be catastrophic to the logic. It's never good to make the reading developer think very hard. – jpmc26 May 30 '18 at 23:50
  • @jpmc26 particularly because while the author may have the luxury of thinking about just this bit of code, the maintainer will likely need to keep track of this and N other things related to the behavior they're debugging – Morgen May 31 '18 at 05:20
  • 2
    @jwdonahue: Bracing is a style argument. Separating observation from manipulation is not a matter of style, it's a matter of separating your concerns. If a bug occurs due to short-circuiting evaluation, that inherently proves that the developer who created the short-circuited expression expected a separation of observation and manipulation; but the other developer did not implement this separation. In such a case, I would argue that a need for separation becomes relevant, and we should then err on the side of separating (this is the same argument as for any separation of concerns/dependencies) – Flater May 31 '18 at 07:47
  • @jwdonahue: Just to be clear: it's okay for a development team to explicitly allow mixing observation/manipulation; but this should be _explicitly stated_ as a rule/standard, which then effectively disallows any developer to use short-circuiting. In the face of a separation-related bug (or developer with a pro-separation mindset), and in absence of an explicit rule that argues against separation, the best approach is to implement the separation. – Flater May 31 '18 at 07:54
  • 5
    "Some terms in a logical expression can have side effects" - While this opening statement is correct, I feel this answer fails in not pointing out that _relying on side-effects is bad_. Far worse, in fact, than relying on short-circuit evaluation to prevent spurious evaluations. Which this answer does suggest may be bad form. – aroth May 31 '18 at 09:01
  • @aroth The whole point of short-circuit evaluation is to prevent spurious evaluations. If you don't like it, you don't have to use it. – Luaan May 31 '18 at 11:06
  • 1
    Yes, that was kind of my point. Short-circuit evaluation _isn't_ bad. Deliberately avoiding short-circuit evaluation because you're relying upon the side-effects of your conditional expressions for your program to work correctly _is_ quite bad. – aroth May 31 '18 at 13:16
  • 1
    @aroth Why exactly is relying on a deterministic and well-defined behavior bad? I'm not saying you are wrong but it would be more useful to explain what's bad about it (e.g. readability). In my experience most developers don't understand what it means when `&` or `|` is used in logical expressions and think they are looking at bitwise logic which is enough reason for me to avoid it. – JimmyJames May 31 '18 at 16:13
  • For a simple example, say someone wrote a `fileExists(path)` method that both checks to see if the file exists, and attempts to create it if it does not. Then they write some code like `if (dataAvailable() && fileExists("myApp.cfg")) { appendData("myApp.cfg"); } read("myApp.cfg");`. The method causes file-creation as a side-effect, and with no short-circuit evaluation it's always called and therefore `myApp.cfg` will always exist by the time `read()` is called. However... – aroth May 31 '18 at 23:27
  • ...a developer who either 1) doesn't understand that short-circuit evaluation is _not_ happening here or 2) that `fileExists()` has a non-obvious side-effect may look at that code and _wrongly_ conclude that "it's obvious that `myApp.cfg` always exists here, so that call to `fileExists()` is spurious and can be removed". Or being unaware of the side-effect may decide that `fileExists()` does _only_ what it sounds like and start using it generally to check for files, not realizing that each use is creating a new, empty file in the filesystem. Therefore, relying on side-effects is bad. – aroth May 31 '18 at 23:29
  • The best way to avoid confusing developers with real code that takes full use of the available language features is to not hire stupid developers. Language features dictate the range of available coding styles and mostly non-scientific theories seem to dictate acceptable practices. Yes, coders make mistakes and some common practices can avoid the most common mistakes, but it is also true that the rules intended to avoid them can lead to an entirely different population of bugs and inefficient generation of machine codes. – jwdonahue Jun 01 '18 at 05:21
3

when is short-circut evaluation bad?

They become bad, as soon you start to rely on side effects of expressions you expect to be executed in the evaluation of a boolean overall result.

πάντα ῥεῖ
  • 1,540
  • 3
  • 12
  • 19
1

Caveat: This is a bit esoteric in that in almost all cases, developers shouldn't worry about it. But... there can be a performance hit due to conditional evaluation as it creates branching in execution. A non-short circuit operation does not branch and is more predictable.

The reason this rarely matters is that the cost is typically small and also usually outweighed by the cost of evaluating the second (or third, etc.) condition. This will only ever matter in computationally expensive routines when high-performance is required and it might still not matter then either.

JimmyJames
  • 24,682
  • 2
  • 50
  • 92
  • I think you can only optimize a logical statement so far, eventually you have to take branches. – jwdonahue May 30 '18 at 19:41
  • @jwdonahue I don't get your point. Sorry. – JimmyJames May 30 '18 at 19:42
  • We're talking about combinatorial logic here. Short circuit evaluation or not, you have one or more terms that must be evaluated depending on the result of an earlier term. Hence, branching is involved. – jwdonahue May 30 '18 at 19:48
  • 2
    @jwdonahue Of course but every short-circuit is an additional branch. In certain scenarios executing two expressions (for example) is faster than checking the result of the first before executing the second even if it's often the case that the second is irrelevant. Again, this is rarely important. The case someone made to me for this was for things like matrix multiplication where you have lots of simple evaluations. – JimmyJames May 30 '18 at 20:57
  • The case where the short-circuit evaluation mechanism can be bad, is where there needs to be side effects for more than one term in the expression evaluation. In other words, all side-effects must happen before deciding to take the one branch. Where there are no side effects involved, the compiler can generate speculative branch execution and there will still only be on decision point, so yes, you are pointing out an esoteric circumstance where there are no side-effects and the compiler or the CPU can't do speculative execution. – jwdonahue May 30 '18 at 21:22
  • Basically, there's a slight chance of a performance hit in the case where all the terms are evaluated in the normal case, as opposed to only occasionally being short circuited. In that case, there's an extra conditional branch for each term in the expression. I suppose I agree with you on that point. – jwdonahue May 30 '18 at 21:25
  • 1
    I updated my answer with credit to you. – jwdonahue May 30 '18 at 21:38
0

Pascal didn’t define whether AND and OR use short circuit evaluation or not, giving you the worst of both worlds.

C and C++ have bitwise operations & and | which in practice give you non-short circuit operations. And compilers are free to evaluate any way they like if it doesn’t make an observable difference.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
  • @Deduplicator: As noted, Pascal *didn't define* whether AND/OR use short-circuit evaluation. That means "not knowing". – supercat May 30 '18 at 23:09