Old knowledge can become valuable in a new context. The 19th century De Morgan’s Laws is a splendid example of that. Belonging to the theoretical propositional logic I doubt it had any significant applications back then. Nowadays within programming it can really help.
The law is about equivalence for logical constructs.
The laws can be rewritten into C/C++/C#/Java code.
!(P && Q) // Is Identical to !P || !Q !(P || Q) // Is Identical to !P && !Q |
I prefer to think of them as “swap &&
and ||
and negate everything”. Knowing them can help unwind complex conditions.
An Access Control Example
An example of where I’ve recently used De Morgan’s Laws is in a piece of code for access control. Originally it was written by negating the access allowed cases and then checking if the user is admin.
if(!(currentUser == creatorId || currentUser == customerId) && !isAdmin) { Console.WriteLine("Access denied!"); } |
I find that piece of code hard to read. Using De Morgan’s Laws, it can be rewritten in two ways. I find both of them easier to read than the original.
// Apply the law to !(currentUser == creatorID || currentUser == customerId). // It's easier to read and focuses on the conditions required to deny access. if(currentUser != creatorId && currentUser != customerId && !isAdmin) { Console.WriteLine("Access denied!"); } // Apply the law to && before !isAdmin to turn everything into or. // It's easier to read and focuses on the what gives access and then negates that. if(!(currentUser == creatorId || currentUser == customerId || isAdmin)) { Console.WriteLine("Access denied!"); } |
The rewrites above are not that hard to make without knowing a more than 100 years old theorem, but to me it requires more effort. Whenever I simplify a condition using De Morgan’s Laws, I stop care about the meaning of the condition. I can focus on the syntax of mechanically swapping some operators, knowing that the meaning is kept the same. It might not be the most revolutionary thing to make the rewrites above, but every single line of code that’s easier to read and understand reduces the risk for bugs.
Sometimes I also find conditional execution easier to read than boolean logic. If the boolean expressions are flat you can rewrite them using if. It will be more code, but easier to follow.
The above example would be: