Question

I'm writing a Scheme interpreter. For each built-in type (integer, character, string, etc) I want to have the read and print functions named consistently:

READ_ERROR Scheme_read_integer(FILE *in, Value *val);
READ_ERROR Scheme_read_character(FILE *in, Value *val);

I want to ensure consistency in the naming of these functions

#define SCHEME_READ(type_) Scheme_read_##type_
#define DEF_READER(type_, in_strm_, val_) READ_ERROR SCHEME_READ(type_)(FILE *in_strm_, Value *val_)

So that now, instead of the above, in code I can write

DEF_READER(integer, in, val) 
{ 
 // Code here ...
}

DEF_READER(character, in, val) 
{
 // Code here ...
}

and

if (SOME_ERROR != SCHEME_READ(integer)(stdin, my_value)) do_stuff(); // etc.

Now is this considered an unidiomatic use of the preprocessor? Am I shooting myself in the foot somewhere unknowingly? Should I instead just go ahead and use the explicit names of the functions?

If not are there examples in the wild of this sort of thing done well?

Was it helpful?

Solution

I've seen this done extensively in a project, and there's a severe danger of foot-shooting going on.

The problem happens when you try to maintain the code. Even though your macro-ized function definitions are all neat and tidy, under the covers you get function names like Scheme_read_integer. Where this can become an issue is when something like Scheme_read_integer appears on a crash stack. If someone does a search of the source pack for Scheme_read_integer, they won't find it. This can cause great pain and gnashing of teeth ;)

If you're the only developer, and the code base isn't that big, and you remember using this technique years down the road and/or it's well documented, you may not have an issue. In my case it was a very large code base, poorly documented, with none of the original developers around. The result was much tooth-gnashing.

I'd go out on a limb and suggest using a C++ template, but I'm guessing that's not an option since you specifically mentioned C.

Hope this helps.

OTHER TIPS

I'm usually a big fan of macros, but you should probably consider inlined wrapper functions instead. They will add negligible runtime overhead and will appear in stack backtraces, etc., when you're debugging.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top