Inverting Logical Expressions


Part of our day-to-day tasks is to do code refactoring. As part of this process, I’m sure that many of us have had to negate the logical expressions in if or while statements at least once. For example, we may want to change this code:

if logged_in
  # do something when logged in
else
  # do something when not logged in
end

into something like this:

if !logged_in
  # do something when not logged in
else
  # do something when logged in
end

This is indeed a very simple change, so consider this other example:

# Original
if (age >= 18 && age < 21)

# Negated
if !(age >= 18 && age < 21)

This works and it’s perfectly valid, but it’s not always the best thing to do. Long expressions with a negation at the start are hard to read, and this is not the code I’d like to debug when there’s a production bug at 3 am.

As you may have noticed already, this is a better way to negate that expression, as it greatly improves its readability:

if age < 18 || age >= 21

And things may get more complicated as we add more conditions to our statement, like:

if (admin || (retry < 15 && retry >= 3)) && !logged_in

The interesting thing is that we have a simple set of rules that dictate how to negate our conditions. Let me introduce you to De Morgan’s laws.

The De Morgan’s Laws

Although Augustus De Morgan was not the first to come up with the laws that take his name, he is recognised for being the first to state them in terms of modern formal logic [1]. These rules can, however, be expressed in simple English as follows:

  1. The negation of “A and B” is the same as “not A or not B”.
  2. The negation of “A or B” is the same as “not A and not B”.

In code, we could write them as:

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

Let’s consider some examples to see how these rules can be used:

Applying The Laws

The first law is indeed very simple to apply:

# Original
if (logged_in && has_permission)

# Negated
if !(logged_in && has_permission)

# Applying the first law
if (!logged_in || !has_permission)

And so is the second:

# Original
if (email_valid || phone_valid)

# Negated
if !(email_valid || phone_valid)

# Applying the second law
if (!email_valid && !phone_valid)

Things get more interesting with more complex expressions. In this example, we’ll negate an expression that combines && and || operators. Note that in this example I apply the laws in two steps to show how the negation can be propagated into groups of parentheses, while having the same logical meaning at all times.

# Original
if (can_view || is_admin) && status == "active"

# Negated
if !((can_view || is_admin) && status == "active")

# Applying the laws
if (!(can_view || is_admin)) || !(status == "active")
if (!can_view && !is_admin) || status != "active"

We can also apply the law to relational operators, like in the example below:

# Original
if (age >= 18 && age < 21)

# Negated
if !(age >= 18 && age < 21)

# Applying the laws
if !(age >= 18) || !(age < 21)
if age < 18 || age >= 21

Wrap Up

The De Morgan’s laws give us easy to follow steps to effortlessly invert the most complex logical expressions in our code.

However, I’d be really worried if my code was full of lengthy, complex expressions. Maybe one or two are unavoidable, but if your conditional are growing big, consider refactoring your code to avoid them in the first place.

If you decide to change your code, be it to invert a conditional or simplify it, I would highly recommend using unit tests to ensure that the code works as expected before and after the refactor, as no laws discovered to date are able to prevent human error.

Cheers,
José Miguel

Share if you find this content useful, and Follow me on LinkedIn to be notified of new articles.

References

[1] Formal Logic: or, The Calculus of Inference, Necessary and Probable. De Morgan, 1847.
[2] De Morgan’s laws – Wikipedia


One response to “Inverting Logical Expressions”

  1. Thank you for your great article on De Morgan’s laws! The clear explanations and practical examples made the concepts much easier to understand

Leave a Reply

Your email address will not be published. Required fields are marked *