It's a tradeoff. Let me give an example. I stumbled on the technique of differential execution around 1985, and I think it's a really good tool for programming user interfaces. Basically, it takes simple structured programs like this:
void Foo(..args..){
x = y;
if (..some test..){
Bar(arg1, ...)
}
while(..another test..){
...
}
...
}
and mucks with the control structure like this:
void deFoo(..args..){
if (mode & 1){x = y;}
{int svmode = mode; if (deIf(..some test..)){
deBar(((mode & 1) arg1 : 0), ...)
} mode = svmode;}
{int svmode = mode; while(deIf(..another test..)){
...
} mode = svmode;}
...
}
Now, a really good way to do that would have been to write a parser for C or whatever the base language is, and then walk the parse tree, generating the code I want. (When I did it in Lisp, that part was easy.)
But who wants to write a parser for C, C++, or whatever?
So, instead, I just write macros so that I can write the code like this:
void deFoo(..args..){
PROTECT(x = y);
IF(..some test..)
deBar(PROTECT(arg1), ...)
END
WHILE(..another test..)
...
END
...
}
However, when I do this in C#, somebody in their wisdom decided macros were bad, and I don't want to write a C# parser, so I gotta do the code generation by hand. This is a royal pain, but it's still worth it compared to the usual way of coding these things.