Is !(p && q) exactly the same as !p || !q?

And then there’s Perl, which has “||” “&&”, “and” and “or” operators, with the differences not in short circuiting but rather in precedence. This encourages certain types of idiomatic programming. For instance, this dies:
print ‘0’ || die ‘print failed’;

But this works because “or” has a very low precedence (lower than argument binding):
print ‘0’ or die ‘print failed’;

Of course, this would have worked as well, but isn’t quite as nice looking:
print(‘0’) || die ‘print failed’;

TriPolar, I don’t think we disagree but I’m a little confused about what you’re saying. Originally when I gave the example



if (p != NULL && p->x == y) ...


and said that that short circuit evaluation was useful for cases like this, you seemed to disagree and said that the feature was mainly for performance. Then later you said “The example used is quite simple and easily recognizable to C programmers…” Were you again referring to my example? So you agree that my example is acceptable but more complicated cases wouldn’t be? I certainly agree that relying on long complicated chains of logical connectives can become unmanageable. But I would definitely say that avoiding a case like this example simply because it relies on short circuiting, which is what I thought you were saying, would be going much too far in the other direction.

Dr. Strangelove, I would agree with all your examples (the first is identical to mine). And I also am finding that multiline code blocks are not working on this board, which is quite annoying.

That’s not true for languages other than C.

FORTRAN placed a much higher emphasis on code efficiency than C did (and FORTRAN code was always much faster than C code). A minor feature of this was that the language allowed both reordering and short-circuit evaluation.

Sure, there’s nothing wrong with that specific form because it’s so simple and recognizable. Certainly someone could screw it up but at that point they’d screw up anything. I work with a lot of young programmers, in house and among our customers, and they don’t have a strong sense of these language intracacies like we do, they have little experience programming from the ground up, they’re moving rapidly among different platforms and, they expect tools to do most of the work for them. Unfortunately they also move on quickly leaving behind code that leaves a lot to desired for the long term.

and things like this is why even tho I love learning about them I decided when I was 8 or 9after making my own games in basic on a ti-99/4A and on a tandy color computer 3 apple 2e and commodores 20 and 64 that when I got a job making computer games id be the guy that wrote the story and drew the pretty pictures then handed them to the code monkeys and say make this playable …

To be clear, when I suggested adding parentheses, I meant only when the order of operations might be unclear. In a statement like


if(x < y + 1) ...;

nobody would think that that means “compare x and y, and then add one to the resulting Boolean”. Everyone knows that in any sane language, numerical arithmetic comes before comparison in the order of operations. But suppose instead you had something like “If it’s either B, or both A and C”? You could, if you know that C’s order of operations evaluates && before ||, write


if(a||b&&c) ...;

But it’s probably clearer, even though the parentheses are unnecessary, to write


if(a || (b&&c) ) ...;

In other words, when in doubt, add parentheses… but when not in doubt, don’t.

As for idiomatic programming, maybe it’s different for professionals, but as an occasional incidental coder, I find that I know enough languages that I can mostly pick up new ones on sight… except for idioms like short-circuiting.

I’ll go against the flow and say that I’m parentheses-mad, and will put them in even for (x < (y + 1)).

The reason is that parentheses have nearly the same purpose as spacing, capitalization and punctuation have in written text. ICANWRITELIKETHISANDYOUCANSTILLFIGURETHINGSOUT. But it’s better if I put in spaces and such, because part of reading efficiently is looking at words and even phrases as a unit.

Parentheses are a visual indicator that I can treat something as a group. I don’t have to scan the inside at all; I can just skip to the matching bracket and know that it’ll be treated as a unit. With the bare minimum parentheses, I have to scan through the entire thing.

I also use spacing and newlines to help in this way; for example, if I have a bunch of similar tests, I’ll put them each on their own line and use spaces to line up the columns. Again, it makes quick scanning easier and is a visual hint that the tests are all the same sort of thing.

BTW, to whom it may constern: Although the [noparse]


 ... 

[/noparse] tag is fucked up in this new skin (and TPTB apparently don’t give a damn to fix it), you can equally well use [noparse]

 ... 

[/noparse] to display your code. It works exactly as it ought to and you get to see pretty carnival colors too!


if (foo()) { /* only valid when foo() is true */ 
    if (bar()) { }
}  

Going back to the OP’s comment about imprecision and English.

One of the challenges when learning about programming Boolean logic vs English is that in English the word “or” is generally the exclusive or. Whereas in programming it’s the inclusive or.

For example: “The daily special is meatloaf with potatoes and soup or salad”

In that English construct there are two valid meals: (meatloaf, potato, soup) , (meatloaf, potato, salad).

In Boolean logic (meatloaf, potato, soup, salad) would also be a combo that evaluates Meal.IsValid to true. But try getting the waitress to bring you that without an upcharge and see how far you (don’t) get. :slight_smile:

It’s also true that in English the “order of evaluation” is ambiguous.

If we say “The daily special is meatloaf with potatoes and soup or salad” is that “The daily special is meatloaf with potatoes and (soup or salad)” or is it “The daily special is meatloaf with (potatoes and soup) or salad”? That one seems pretty obvious. But what about “The daily special is meatloaf with soup or salad and potatoes”?

Breakfasts get even more complex where you need outside rules about common food combos to parse out which items are the omelet ingredients, which are the starch substitutions, and which are the multiple helpings of different starches / carbs.

Bottom line: if you’re reading or writing code as if it was English you’re importing a lot of fuzzy thinking the compiler won’t apply to your work.

If truth values are strictly binary, then ‘exactly same.’ But* intuitively* logic values are often fuzzy.

Nope. C conforms to very strict rules on whether it does the “short-circuiting” or not. In OP’s examples, the two evaluations will have identical side effects. (Though a reversal — e.g. !q || !p — will not.)

C’s short-circuiting is ocasionally convenient when it leads to terser code than the equivalent if/else, e.g.
if (p && p)[INDENT]foofoo(p); / executed only if p is non-null AND non-empty */
[/INDENT]

Of course, by the programming interpretation, meatloaf, spam, mashed potatoes, spam, spam, soup, spam, salad, spam, arsenic, and spam is also a valid meal, since it includes meatloaf, mashed potatoes, and at least one of soup or salad.

Way, way back when I talked to an instructor at UofP who was teaching the introduction to computer course there. Very few people in the 70s had any sort of exposure to computers. He considered at the time that the use of common words and terms in computer languages was a hindrance to learning the basics because of the informal concepts people already held. At the time he found many people didn’t understand what even ‘input’ and ‘output’ meant in a computer sense because they viewed the words from there own point of view. For instance they considered something printed on a computer to be input because it was information given to them. Times certainly have changed though, through both direct use of computers and their incorporation into everyday life these concepts are more well understood and part of early education, but when it comes to logical operators there’s still plenty of confusion for people that don’t have programming experience.

OTOH, color me as somebody who despises the use of “if (!p)” to mean “if(p != NULL)” Also the idea that any data type other than Boolean can be silent-cast to Boolean under the {zero -> false, non-zero -> true} rule. Or is that the {low order bit = 0 -> false, low order bit = 1 -> true} rule? Or the {high order (sign) bit = 0 -> false, high order / sign bit = 1 -> true} rule? Or the {low order nibble = 0x0 -> false, low order nibble = 0xf -> true, else indeterminate} rule?

Any of which is valid depending on which language and which processor.

As **Tripolar **said a few posts back, the modern reality of commercial programming is that workers don’t spend 20 years in one language on one OS & processor. They don’t become totally immersed in the quirks and conventions of that narrow environment. Instead they’re expected to jump from Java to Ruby to .Net to javascript to this, that, or the other library with no training and little spin-up time. Modern website development frequently requires the same dev to be fluent in 2 or 3 or 4 languages / environments at once.

Saving 3 keystrokes and hoping you/they remember the <whatever quirk> rules correctly seems like false economy in that environment. Firstly in the writing of the code, but 10x (or is it 50x?) in the lifecycle maintenance cost of that code.

Somehow this loses it’s jovial feeling outside of the pit.
Since by rule **Mr. Nylock ** cannot return the favor and call me a POS here I’m going to go ahead and retract my previous statement. Which in my little warped mind I believe I can save that statement for more deserving posters.

100% agree with this. Simple, obvious, readable is far more important than saving a few keystrokes, especially given that we are hopping between so many languages regularly.

I was led to understand that & and | are arithmetic masking operators that are always fully evaluated, whereas && and || are logical operators that do short-circuit. For instance, 42&7 returns 2 and 42|7 returns 47: you can & two true values and end up with false (e.g., 42&6 = 0). You should probably never use & or | for logical constructions, opting instead for && and ||, unless you know exactly what you are doing.

Thank you kind sir.

Argh, that should have read “42&5 = 0”.

As a computer science instructor at a community college, after spending 25+ years programming in C at a large three-letter computer corporation, I’m enjoying this discussion immensely.

Our course sequence is Python -> Java -> C, and it was recommended that our students be exposed to at least two different languages (we also have them use JavaScript, jQuery, and PHP). You should see the students’ jaws drop when they see the **while (*d++ = *s++); ** C construct. I make them deconstruct into Java (as closely as possible!) just to show them why C programmers do that thing they do.

And yes, we spend several discussions on DeMorgan’s law until they finally get it. Then I get to show them C’s short-circuiting. Blows their minds again. I love it!

You’re lucky this still isn’t in the pit buddy.:mad: