Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

Licensed under: CC-BY-SA with attribution
scroll top