10

We all know De Morgan's Laws

!(a && b) === (!a || !b)
!(a || b) === (!a && !b)

Is there a community consensus around which one of these representations is easier to reason about (and therefore) produces more maintainable code? If there is not, what is this community's opinion?

Abraham P
  • 269
  • 2
  • 8
  • 4
    `#define a notConnected \n#define b notOnline` would change your semantics and readability entirely. So without stating what your variables are *supposed to mean* (i.e. are they "positive" or "negative" logic) the question doesn't make a lot of sense. – tofro Jul 31 '17 at 13:18
  • 1
    @tofro, which in summary would mean: Write your code in order to be easy to read. +1 to your comment. – Machado Jul 31 '17 at 13:22
  • Possible duplicate of [How would you know if you've written readable and easily maintainable code?](https://softwareengineering.stackexchange.com/questions/141005/how-would-you-know-if-youve-written-readable-and-easily-maintainable-code) – gnat Jul 31 '17 at 13:33
  • 2
    Unlike sweat pants, one size does _not_ fit all when writing code. –  Jul 31 '17 at 14:13

3 Answers3

12

This is somewhat subjective, but a good general rule of thumb is to remove as much complexity as possible. By complexity, I mean the number of operations you need to perform in order to obtain the desired result.

In this sense, !a && !b is worse than !(a || b) because in one case you're negating a and b, then performing the and operator resulting in 3 operations whereas in the latter case, you're only performing 2. Of course this is vacuous when you're talking about two conditions, but when you're dealing with many, this can make a big difference.

Ideally, the form of your conditions would be either in the form a || b || c or a && b && c, adding parentheses as necessary. Try to avoid forms like !(a && b) || (b && (c || d || !a)) as it is very difficult to decifer the meaning without creating a truth table.

Also, it is generally a good idea to avoid "not" in variables holding conditions, even if it adds complexity.

In other words, it is better to see isWet = raining && !hasUmbrella && !isInside than to have isNotWet = !raining || hasUmbrella || isInside, because it's easier to rationalize the meaning of variable isWet than isNotWet. You can always negate isWet to achieve the same value of isNotWet.

Neil
  • 22,670
  • 45
  • 76
  • 1
    `isWet = raining && !(hasUmbrella || isInside)` is much easier for me to read than either of your examples. It follows your first rule of thumb, so there seems to be some merit to it! – Jacob Raihle Jul 31 '17 at 15:02
  • 1
    `isDry` is as clear to me as `isWet`. – Reinstate Monica Jul 31 '17 at 21:27
  • @Solomonoff'sSecret You got me. Bad example. Though you're not always going to have an exact opposite. My point was simply to avoid adding not in the name, preferring instead to negate the expression entirely. – Neil Aug 01 '17 at 06:25
8

With such representations, readability and understandability of the code and meaning are paramount.

There is no consensus on which of the two is better, because it very much depends on the actual bit of code - naming conventions and so on.

But - in general, it is better to avoid multiple negatives in one expression - it is easier for people to reason about positives instead of negatives (though, your examples have the same about of negatives in them).

When coding - look at both expressions and see which one flows better, which one conveys the meaning best. Sometimes - it is better to extract a complex Boolean expression (say each side of the ===) into its own little, expressively named function - which makes the end result very readable.

Oded
  • 53,326
  • 19
  • 166
  • 181
0

From the logical standpoint, the statements on each side of == sign are are equivalent, so it makes absolutely no difference which one is used.

From the code readability standpoint, a rule of thumb that I like use is to choose the boolean expression that makes more sense when spoken out loud. For instance, the first law can be translated as:

If at least one is not true

This can be said as:

  • if it is not the case that both are,

or

  • if one of them is not or the other one is not

The second law can be translated as:

If neither one is true

This can be said as:

  • if it is not the case that at least one is,

or

  • if one of them is not and the other one is not either

Which one you should choose in the particular case depends on which sentence makes most sense to you. Logically, they are completely equivalent.

Vladimir Stokic
  • 2,943
  • 14
  • 25