Simplifying boolean expressions

i was doing a little fun C# coding on the side and i was running into one of those cases where i had a conditional expression to write and i couldn't figure out the best way to write it.  it was basically something like:

void Foo(a, b) {
if (!((a && !b) || (!a && b))) {
//do stuff
}
}

i was sitting there playing with this expression until i realized that it could be reduced to just "if (a == b)".  After that i was thinking "it would be nice if this could just be taken care of for you".  Similarly we could transform expressions like:

if (a > b || a == b) { //...

into

if (a >= b) { //...

Or could we...

interestingly enough we might not actually be allowed to do that.  Why?  Well lets say the user had written their type with the following members:

bool operator >(T t1, T t2) { return true; }
bool operator ==(T t1, T t2) { return true; }
bool operator >=(T t1, T t2) { return false; }

(egads!  Legal, although discouraged).

Now we've gone ahead and changed the legal meaning of your code. 

Here's another example:  Say we tried to transform the following expression:

if (a > 0 || a > 0) { //...

into

if (a > 0) { //...

Seems fine, but actually it might not be.  Here's how:

int _a;
int a { get { return _a++; } }

So, in order to get something like this right it seems like we'd have to go deeper than just looking at the parse structure of the code, and we'd have to go deeper to examine the semantics behind it.  in the first case we can't assume that overloaded operators have the same combinatoric semantics that we're used to with most of the builtin types, and in the second the expression has side affects, so reducing it will not preserve those changes.  Luckily the compiler can at least tell us if an expression leads to executable code, and in that case we can just assume the expression is unsafe to manipulate. 

Of course, it's quite possible that one might want to still go through with the transformation because they know that it's safe for their domain.  For example, this would allow them to simplify:

if ((!((Foo() && !Bar()) || (!Foo() && Bar()))) { //...

into

if (Foo() == Bar()) { //...

This would be OK as long as the user was confident that the semantics of those operators expressions are the same as if they were just dealing with simple boolean expressions.

So i figured i'd provide two expression manipulation tools.  One to just simplify the expression "safely" and one to simplify it "aggressively" as per the caveats i listed above. 

i'd also want to be able to handle code of the form:

if (a) {
if (b) {
c;
} else {
d;

   }
} else {
d;
}

and transform it into:

if (a && b) {
c;
} else {
d;
}

So now, how do i go about doing this?  Well, the next post will go into the prototype i wrote to get it done.

 If you'd like something like this in the IDE, let me know!

 


 

Edit: Note that this is not about showing you optimizations that can be done with your code.  This is about allowing you to take an overly complex and confusing bit of code and being able to rewrite it into a form that's much more clear and maintainable.  In the first example i had rather than having to put down some complicated implication rules i was just able to use a simple equivalence which not only was incredibly easy to read but it also helped me understand better what the code meant that i was writing at that point.