Monday, 29 September 2008

Beautiful code

What is beatiful code? The shortest answer (which I've read somewhere but can't remember where) is:

we all know what "ugly code" is: code that someone else wrote...
But beautiful code? Isn't it in the eye of the beholder? Well, for me, beautiful equals readable. You have to see on the first sight what the overall idea of the piece of code is. On the other side, the idea itself might be crap (!!!) but then we should ask the next question: what is a beautiful design/architecture?

I, for my side, am thus a proponent of writing aesthetically appealing code. And I'm not alone! Read this:

Whether it is a natural occurrence, a quirk of human languages, or conditioning, most people find while (x==3) significantly simpler to read than while (3==x). Although neither is going to cause confusion, the latter tends to slow people down or interrupt their train of thought. In this book, we have favored readability over safety—but our situation is somewhat different than that of normal development. You will have to decide for yourself which convention suits you and your team better. *
Here we've got it: the eternal problem with the coding guidelines forcing me to write a plug-ugly (3==x)! The question is: should we write ugly code as to be on the safe side? I admit, that I never wrote such an ignominious line of code in my life. You expect trouble? Nope! I've never had any problems at this point! Well, one single time I mistyped it, but found it out in an instant! In C++ you have to develop certain sensitivity for that construct, that's all.

As for practical examples (instead of dull theoreticizing) - some time ago I asked myself: what is the most cool/beatiful piece of code you eve wrote, what would you show to others in order to impress them or to show them how crystal-clear ;-) your style is? As it was even before my lambda library, and only had plain production code on my disposal, I settled on the following piece:
/*------------------------------------------------------------------------*/ /**
* @brief configDelta
* @descr
* This function compares two configurations and returns the differences.
*
* @param[in] other - the other configuration
* @param[in] scope - what delta requested: all the new entries, all the deleted
* entries, or all changes altogether?
* @param[out] delta - the calculated diffrence
*
* @note Assumption: both configurations must be sorted!!!
*///--------------------------------------------------------------------------->

void SimpleCfgFile::configDelta(const SimpleCfgFile& other, CfgDelta scope,
vector<string*>& delta) const
{
TRACE_FUNC("SimpleCfgFile::configDelta");
delta.clear();

switch(scope)
{
case addedDelta:
TRACE_DEBUG("addedDelta");
// all in this but not in other:
set_difference(begin(), end(),
other.begin(), other.end(),
inserter(delta, delta.begin()),
less_then_deref<string*>());
break;

case removedDelta:
TRACE_DEBUG("removedDelta");
// all in other but not in this:
set_difference(other.begin(), other.end(),
begin(), end(),
inserter(delta, delta.begin()),
less_then_deref<string*>());
break;

case completeDelta:
TRACE_DEBUG("completeDelta");
// all in this but not in other + in other and not this:
set_symmetric_difference(begin(), end(),
other.begin(), other.end(),
inserter(delta, delta.begin()),
less_then_deref<string*>());
break;

default:
TRACE_ERR("Unknown scope requested for configuration delta!!!");
}

TRACE_VALUE(delta.size());
}
You see, it's not a rocket science. What I liked in this piece of code was it's conciseness, readibility and (though it's of no real importance for workings of the code) its symmetry. And moreover, I was amazed how a judicious usage of the standard library simplified the task which at first seemed to be rather a daunting one!

An lastly, it's an illustration for the fact that you don't have to use a lambda library to obtain a clear code: I just wrote the following trivial functor:
  template <class T> struct less_then_deref : binary_function<T,T,bool>
{
// OPEN TODO ---> constraint: isPtrType(T)...
bool operator() (const T& x, const T& y) const { return *x < *y; }
}
instead of the lambda expression (*$1 < *$2) and it is still readable. Or even more readable by using a telling name?

---
* taken from the following book: Groovy in Action, Dierk König et al., Manning 2007, page 157-158

1 comment: