Derived Data

From SelfDocumentingCode.

When data is redundantly maintained, don't. Instead, derive the redundant copy from other sources.

[Huh? "When data is redundantly maintained, don't [be redundantly maintained]"? Perhaps you mean "When you maintain data redundantly, don't"? ]

See also OnceAndOnlyOnce.

Many times when writing code you discover that you need two very similar sets of data. Typically, one set can be derived from the other. Instead of maintaining both sets independently by hand, which is errorprone, maintain only one and derive the rest of the data automatically.

For instance, it is an unfortunate common practice to write

 #define SIZE 100

char array[SIZE]; int i;

for( i = 0; i < SIZE; i++ ) { /* do something with array[i] */ ; }

However, it is far superior to write

 #define SIZE 100

char array[SIZE]; int i;

for( i = 0; i < sizeof array / sizeof *array; i++ ) { /* do something with array[i] */ ; }

as the size of the array comes for free from the compiler (with some sizeof magic). Note, while the sizeof(char) is strictly 1 by ANSI, you may which to change the type of the array in the future. Say, to wchar_t.

Indeed, a handy macro I use for this particular incarnation of DerivedData is:

 /* Returns the size of an array defined in local lexical scope */
 #define NUM_ELEM(x) (sizeof (x) / sizeof *(x))

The moniker violates MeaningfulNames?' corollary about abbreviations, but it is such a common operation, it needed to be short.

Similar sizeof magic is something along the lines of

 pFoo = malloc( sizeof *pFoo );

That way you can be immune to changes to pFoo's type.

Other interesting ways of using DerivedData would be defining XML tag names to be identical to class names that you can instantiate through reflection to actually read in the object. That way you don't have to maintain a separate table of class <-> tag associations.

Basically, like many SelfDocumentingCode techniques, this boils down to simplification. If you don't have to document, "change that when you change this," your document/comments are that much thinner.

Fascinatingly, many people fail to extend this notion towards actual documentation, relying instead on manpower generated diagrams updated through traceability. However, your suggestions make the code more difficult to read. The first for loop example is far more intuitive, and thus superior. Also, even though I programmed C for several years, it's not obvious to me whether your examples will work in all circumstances with all compilers.

    Technically some compilers don't parse sizeof operand correctly, instead requiring sizeof(operand). The NUM_ELEM macro does work properly in all environments I have ever used, but if you're paranoid, you could further guard it by surrounding the *(x) with a further set of parentheses.

/* Returns the size of an array defined in local lexical scope */ #define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))

Does this complication affect you? Not really. Does this matter to the point above? Definitely not. Broken compilers only break the examples, not the Pattern.

Perhaps if the macro name was SIZE_OF_ARRAY it would be easier to read. I would certainly question the readability of

pFoo = malloc( 48 );

or even

pFoo = malloc( sizeof Foo )

especially if pFoo had been changed in maintenance to be a FooSubclass? whose size > sizeof Foo. In other words, it's lying and therefore unreadable, not to mention broken.

"More on Getting the Number of Array Elements" http://blogs.msdn.com/the1/archive/2004/05/07/128242.aspx and More on Getting the Number of Array Elements http://blogs.msdn.com/the1/archive/2004/10/06/238965.aspx starts with the

 #define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))

technique, then improves it with some C++ magic. Is the result so much better that we should post it here and use it from now on (in C++ code)?

moved from DerivedInformation --JonGrover


CategoryRealData

CategoryCee CategoryCeeSharp CategoryCpp

CategoryCodingIssues


EditText of this page (last edited April 18, 2013) or FindPage with title or text search