Well Paired Operations
All "paired" operations should take place at the same level.
What's a paired operation? An operation is paired with another operation if invoking one operation requires the other operation to be invoked. Examples:
Let's look at an example of a set of poorly paired operations. Aaside from the fact that the following code breaks about a billion other best coding practices it is a surprisingly common anti-pattern!
In this context although the malloc and free operations share the same decendent routine - foo - they have differing degrees of separation and are therefore not well paired.
So, who's fault is this? it's the author of formatSomeMemory()'s fault.
Fundamentally, the problem of poorly paired operations is the result of poorly formed APIs. In this case, the author of the API that included the formatSomeMemory() routine did not provide an appropriate routine for freeing the data that formatSomeMemory allocated. The author of formatSomeMemory() is forcing the author of foo() to write poorly paired code!
In reality, the author of formatSomeMemory() and foo() are probably the same person! The reason that this person wrote a poorly formed API is that they inadvertantly broke an even more fundamental well formed coding principle: The user of an API should not be required to have intimate understandings of the internal framework of the API in order to properly use it.
In many cases, since the user is also the developer, this rule gets broken unconsiously. In our case, since the author of formatSomeMemory() knew that it malloc'ed some memory, he innocently added the free to foo and went on his merry way, not knowing he had just created a debugging pitfall for future developers.
So, what might be some alternatives to the malformed API.
Option 1 - Make user responsible for well pairing operations:
Option 2 - Handle well pairing behind the scenes:
In both these examples the paired operations malloc amd free free are now well paired because in both cases they share the same degree of separation from the root routine foo.
I personally prefer Option 1 to Option 2 simply because Option 2 requires good documentation to work properly. I hate documentation, don't you? :)
What's a paired operation? An operation is paired with another operation if invoking one operation requires the other operation to be invoked. Examples:
- malloc / free
- new / delete
- CreateDC / DeleteDC
- MyStartRoutine / MyStopRoutine
- They occur in the same routine (i.e. in the immediate execution scope, not in a child routine)
- They occur in two different routines who have the same degree of separation from a common ancestor
- Others?
void foo ()The malloc and free operations are well paired because they occur in the same immediate execution context.
{
void * someData = malloc (10);
// some code //
free (someData);
}
Let's look at an example of a set of poorly paired operations. Aaside from the fact that the following code breaks about a billion other best coding practices it is a surprisingly common anti-pattern!
void * formatSomeMemory()
{
void * tmp = malloc (10);
// do some stuff
return tmp;
}
void foo ()
{
void * someData = formatSomeMemory();
// some code //
free (someData);
}
In this context although the malloc and free operations share the same decendent routine - foo - they have differing degrees of separation and are therefore not well paired.
So, who's fault is this? it's the author of formatSomeMemory()'s fault.
Fundamentally, the problem of poorly paired operations is the result of poorly formed APIs. In this case, the author of the API that included the formatSomeMemory() routine did not provide an appropriate routine for freeing the data that formatSomeMemory allocated. The author of formatSomeMemory() is forcing the author of foo() to write poorly paired code!
In reality, the author of formatSomeMemory() and foo() are probably the same person! The reason that this person wrote a poorly formed API is that they inadvertantly broke an even more fundamental well formed coding principle: The user of an API should not be required to have intimate understandings of the internal framework of the API in order to properly use it.
In many cases, since the user is also the developer, this rule gets broken unconsiously. In our case, since the author of formatSomeMemory() knew that it malloc'ed some memory, he innocently added the free to foo and went on his merry way, not knowing he had just created a debugging pitfall for future developers.
So, what might be some alternatives to the malformed API.
Option 1 - Make user responsible for well pairing operations:
void * formatSomeMemory(void * mem, int size)
{
// do some stuff to the memory
// (perhaps even reallocing it)
return tmp;
}
void foo ()
{
void * someData = malloc(10);
someData = formatSomeMemory (someData, 10);
// do stuff
free (someData);
}
Option 2 - Handle well pairing behind the scenes:
void * formatSomeMemory()
{
void * tmp = malloc(10);
// do some stuff to the memory
return tmp;
}
void * freeFormattedMemory (void * tmp)
{
free (tmp);
}
void foo ()
{
void * someData = formatSomeMemory ();
// do stuff
freeFormattedMemory (someData);
}
In both these examples the paired operations malloc amd free free are now well paired because in both cases they share the same degree of separation from the root routine foo.
I personally prefer Option 1 to Option 2 simply because Option 2 requires good documentation to work properly. I hate documentation, don't you? :)
0 Comments:
Post a Comment
<< Home