www.digitalmars.com         C & C++   DMDScript  

D - Re: Can we have context functions?

Hi Walter,

Recently I thought a lot of concept which would provide support for logging
and tracking without Cish macroses.

This thoughts led me to the notion of context functions.

DEFINITION. Context function is a function which accepts along  with it's
own parameters several hidden parameters such as FILE, LINE or FUNC. This
hidden parameters are always passed when the function is called and have
values describing the place where call is originated.

Let's suppose that __context keyword enables us to define context function,
and __file, __line, __func are keywords that designate hidden parameters
inside context function.
Now let's look at concepts of using logging and tracking in C and D.

1. Logging - the method to store some information along with description of
it's sourse
============ C

#define LogStr(str)  DoWriteLogStr ( "%s,%d: %s\n", __FILE__, __LINE__,
str )
...
main ()
{
 LogStr ("got here" );
 ...
 LogStr ("got here" );
}

============ D
__context void LogStr ( char[] str )
{
 printf ( "%.*s,%d: %.*s\n", __file, __line, str );
}
...
main ()
{
 LogStr ("got here" );
 ...
 LogStr ("got here" );
}

2. Tracking - the method to determine who called particular function
============ C
#define _malloc(s)  malloc_tracked (s, __FILE__, __LINE__)

void *malloc_tracked ( size_t size, char *file, int line )
{
 printf ("malloc(%d) from %s,%d\n", size, file, line );
 return malloc ( size );
}

main ()
{
 void *p = _malloc ( 10 );
}

============ D
__context void *malloc ( size_t size )
{
 printf ("malloc(%d) from %s,%d\n", size, __file, __line );

 // do allocation here...
}

main()
{
 void *p = malloc ( 10 );
}

========================== end of examples

Note that in D we not only got rid of preprocessor usage and have the
identical behavior, but also eliminated intermediate function
malloc_tracked in the second example.

As I see the implementation for this concept is trivial - pass context
parameters to function just like you pass object pointer to class methods.
The keywords used bear imagination. I don't think that names __context and
others are perfect, but they are relevant to problem being solved.
Another issue is that we need support via version statement in order to find
out whether current function is context or not. Then we could rewrite the
second example as:
/*__context*/ void *malloc ( size_t size )
{
 version(__context) {
  printf ("malloc(%d) from %s,%d\n", size, __file, __line );
 }

 // do allocation here...
}

And now we can turn functions into context functions and vice versa easily.

I would like you to consider the examples given and say your word about it.
Any critique and afterthought are welcome.

Nic Tiger.
Mar 15 2003