June 26, 2005
I know this is mostly just taking something already possible and making it easier, but I thought I'd post about it and see what people say. Probably people here won't like it, I guess.

For the record, I'm not talking about preprocessor style macro functions.  What I am talking about can best be described with a code segment:

template api_macros()
{
   void DEBUG_ARG()
   {
      writefln("arg: %d", arg);
   }
}

void api_function(int arg)
{
   mixin api_macros;

   DEBUG_ARG();
}

That's all well and good, and various macros as used by people in C could be done this way (because the variables only need to be there at time of mixin) and is indeed fairly convenient.

However, the problem comes in when you have this:

void DEBUG_ARGS2()
{
   writefln("arg1: %d, arg2: %d", arg1, arg2);
}

For functions which do not have two arguments named appropriately, this will give an error if it is put in the same template.  The way to fix this is to place it into a second mixin, obviously.  But, when you do that at some point you find yourself doing this:

void api_function(int x, int y, float c, float a)
{
   mixin macros_debug_xy;
   mixin macros_debug_c;
   mixin macros_debug_a;

   DEBUG_XY();
   DEBUG_X();
   DEBUG_A();
}

I'd like to, at this point, note that my example leaves a bit to be desired.  The point is only to be an example - I'm sure most of you have experience with real macros as used in most C and C++ programs, ones that seem more useful or which simplify things much more.

At this point, it's obviously almost worthless to bother with this style of macros, because you're adding so many lines of mixins and such, and creating so many templates.

We might as well use a variadic function or something in this case, but there's a reason macros are popular - again, I'm sure many of you have seen macros that use variables in the current scope "in the wild."

I believe the solution to this, which would be much more appealing to people switching from C imho, is:

macro void DEBUG_ARG()
{
   writef("arg: %d", arg);
}

Which should be exactly equivalent to creating a template with that one function inside it.  Calling said function would be exactly equivalent to a mixin (unless one has already been done) and a call to that/the created function.

This would also give a hint to the optimizer that you probably want this function inlined, even if it is longer than those functions it normally likes to inline.

Ideally, the function would use the same stack, allowing (just as with mixins iirc) the use of alloca() and similar.

Debatably, such functions could add to the stack, much like mixins can - although this I'm sure could be trickier, and could easily be left out because it's less logical in a way.

I know that in many cases macro functions are not necessary, rather they are just easier or simpler.  However, I again believe this would help people switching from other languages, and be a general benefit to the language.

Synonyms for the "macro" token I've mentioned might be the mentioned "compile_time", "static" (except that is already taken), and even "inline" (although imho that should be the optimizer's decision.)  That said, I like "macro" and think it rather unlikely such a token would break many identifiers in use.

Of course, this is basically just using mixins with a nicer syntax, and I admit that's all it is.

Thanks,
-[Unknown]