Clearer Conditionals using De Morgan's Laws

Gabe Berke-Williams

Ever seen a hard-to-parse conditional like this?

def allow_access_to_site?
  ! (signed_out? && untrusted_ip?)
end

Let’s use De Morgan’s Laws to clean it up and see who actually has access to our site.

De Morgan’s Laws

''

Whoa, who’s this De Morgan guy? Augustus De Morgan, in addition to looking like a 19th-century John C. Reilly, formulated two important rules of logical inference. You can check out the formal definition on the Wikipedia page, but here they are in Ruby code:

# First law
!(a && b) == !a || !b
# Second law
!(a || b) == !a && !b

Well hey, it looks like we can use these on our gnarly conditional above. Let’s try it.

Law-abiding Ruby code

Recall that the original conditional was ! (signed_out? && untrusted_ip?). Let’s use the first law and puzzle it out.

# Original
! (signed_out? && untrusted_ip?)
# Conversion using first law. I've added parentheses for clarity.
# a = signed_out?
# b = untrusted_ip?
(! signed_out?) || (! untrusted_ip?)

Here I notice that ! signed_out? and ! untrusted_ip? are double negatives: not signed out, not untrusted IP. Now what they’re really trying to say is: signed in, trusted IP. Let’s simplify further, using better method names.

# Simplify a: (! signed_out?) == signed_in?
(signed_in?) || (! untrusted_ip?)
# Simplify b: (! untrusted_ip?) == trusted_ip?
(signed_in?) || (trusted_ip?)
# Remove parentheses
signed_in? || trusted_ip?

These methods, signed_in? and trusted_ip?, might exist and they might not. Creating them is part of this refactoring. You might even end up removing the signed_out? and untrusted_ip? methods in favor of these new, positively-named methods.

And that’s it. We took a hard-to-parse conditional and made it clearer and easier-to-read using De Morgan’s first law.

Before:

def allow_access_to_site?
  ! (signed_out? && untrusted_ip?)
end

After:

def allow_access_to_site?
  signed_in? || trusted_ip?
end

What’s next

If you found this useful, you might also enjoy: