tags:

views:

106

answers:

5

I worked on a project which involved complex boolean logic. This complexity made the code very efficient, but unfortunately hard to read.

So we laid the logic out as below, which made it easier to see the groups within the compound statements, and also made it possible to add comments to parts of the logic.

(This code isn't real code from the project, the real logic was more complex)

if  (
  //comments here!   
  angle.angle < kQuiteLow 

  && (
   previousAngle.angle > kQuiteHigh
   || previousAngle.time == kUnknownTime
  )

  //comments in here too!   
  && pairedAngle.angle < kQuiteLow 

  && (
   //and here
   previousPairedAngle.angle > kQuiteHigh
    || previousPairedAngle.time == kUnknownTime
  )
 )

Have you ever seen this done anywhere else?
Are there any conventions or style guide recommendations on how to lay out very complex boolean logic?

+6  A: 

I would refactor the code to use external methods to make it easier to read.

if( ValidAngle(angle, previousAngle) && ValidAngle(pairedAngle, previousPairedAngle) )

ValidAngle( angle, prevAngle){
    return angle.angle < kQuiteLow && (previousAngle.angle > kQuiteHigh || previousAngle.time == kUnknownTime)
}
pb
OP did emphasize efficiency so add suggestion that functions be inlined if possible.
Duck
@Duck: Let the compiler handle that. Use a profiler if you have doubts.
Jason
@Jason It's just a suggestion to the compiler that it might reject anyway. Can't hurt to drop a hint unless the code bloat is a concern.
Duck
I appreciate this point of view, and generally it is what i would do.However in some cases i prefer to be able to see the underlying complexity. In the project i mentioned the logic was already wrapped inside a procedure (it was sql not c++). I don't moving the contents of each if condition to a new procedure would have improved readability.
compound eye
whoops: ...don't [think] moving...
compound eye
+1  A: 

One suggestion is breaking the logic into methods. Easier also to transform your comments into the method name, so you won't need them. Or, if they are too complex, they are included in the method documentation.

if (anglesAreOk(...)) { }

public bool analyseAngles() { return angleOk(...) && previousAngleOk(...) && pairedAngleOk(...) }

You got the idea...

Samuel Carrijo
A: 

I agree with samuelcarrijo and pb, extract the complex expressions into either methods or variables.

If you can't extract a method to a meaningful abstraction, you could consider code fragments or blocks.

Ash Kim
A: 

From Fowler's refactoring book, I agree with the advice that complex boolean logic should be replaced with methods with meaningful names, e.g.

if(x && y || !b) { }

vs

if(customerIsRepeatCustomerFromIdaho(x,y,b)){ }

Or a variety of unit tests with meaningful names

e.g.

[Test]
public void CustomersFromIdahoGetDiscountsOnAlternatingTuesdays()
{
  isRepeat=true;isFromIdaho=false;isTuesday=true;
  Assert.AreEqual(Customer.CalclateDiscount(isRepeat,isFromIdaho,isTuesday),.10)
}
MatthewMartin
A: 

How about adding the limits to your classes?

e.g.

if ( angle.isQuiteLow() && previousAngle.isQuiteHigh() && previousAngle.isUnknownTime() )
Anders K.