[fpc-devel] Macro Processing

Joerg Schuelke joerg.schuelke at gmx.de
Sun May 15 17:53:26 CEST 2011

Am Sun, 15 May 2011 13:26:03 +0200 (CEST)
schrieb Daniël Mantione <daniel.mantione at freepascal.org>:

> Feel free to come up with examples and convince us. They need to be 
> examples of code that is much more awkward to write without macro's.
There are no examples. For one reason. If you program pascal the last
20 years you learn to circumvent all possible use cases for an small
macro. How could I write an example? There are no macros. I can only
give you an example if I switch on a hypothetical macro support for
pascal. Would you then be able to see that it is simple done this way??
Or would you say, Oh this should better be done this way.

Lets try to find it out:
	I introduce macro definition by: {$M name(par_list):=mac_text}
	and an expansion by {$E name(par_text)} for shortness.

I am a man who likes to have all debugging messages which i ever
introduces in my code to stay there and to simply vanish if I switch
them off by compiler directive. But this is a lot and I do not need it
anytime. Thats why I introduce a nice debugging level. Which will give
me the information I request. Debugging level 1,2,3,... Because this
gives problems with procedures I introduce an stack of that level
values, therefor I can heighten the debugging level right bevor an
procedure call and lower it on return.

This all I put inside a debug unit and an debug include file.

I have a need for an debug print macro and level switching macros and
pushing and poping macros for the debug level stack. Lets look how
they are defined:

{$M _dp(level,fmt,args):=
  dbgprint(level,{$E dbgxfmt},{$E dbgxargs},fmt,args)

You see from time to time I need extra debug information, which is
conditional defined and goes to the included file, like the above:

{$ifdef EXTRA_INFO}
  {$M dbgxfmt:='%s [%s]'}{$M dbgxargs:=[{$I %file%},{$I %line%}]}
  {$M dbgxfmt:=''}{$M dbgxargs:=[]}

In this include I have too, something like this:

{$ifdef MYDEBUG}
  {$M dp(..):=_dp(..)}
  {$M dl(..):=_dl(..)}
  {$M dpush(..):=_dpush(..)}
  {$M dpop(..):=_dpop(..)}

  {$M dp(..):=}
  {$M dl(..):=}
  {$M dpush(..):=}
  {$M dpop(..):=}


which redirects the real use of the dp, dl, dpush and dpop macros to the
real working ones, or nothing, if switched off.

The dbgprint, dbglevel,dbgpush and dbgpop functions which are called
reside in my debug-unit, string formatting and that stuff, there. 

Additional I put:
{$ifdef MYDEBUG}
  {$M usesdebug:=use debug;}
  {$M usesdebugand:=use debug,}
  {$M usesdebug:=}
  {$M usesdebugand:=use }

into my debug.inc file. All I have to do now is writing a program
where I use it:

{$I debug.inc}
program test001;
  {$E usesdebug}
{ or, if I have more used units 
  {$E usesdebugand}

procedure testproc;
  {$E dp(1,'%s',['testproc called'])}
  doing some complex things with more debug output of higher level

  {$E dl(1)}
  do some things
  {$E dl(3)}
  do some things

If I need more debug info I switch the level of debugging, if I need
high level debug from one function only I push the old level:

  {$E dpush(6)}
  {$E dpop}

and pop it back on return.

And if I am ready, I compile it without -dMYDEBUG. But the source stays
unaffected. A month later I possibly have a need for.

You will say this looks like C programming or the macros are expanded
with bad syntax, thats intentionally, you can reach the same with the
simpler expansion syntax. And I DO USE IT. AND IT WORKS FINE.

This is a real working example from the real world. I use it in my
programs similar defined with the crutch of macros fpc has today!!
And this will never work with inline or whatever you may suggest.

- function with array of const arg not inlined (yet)
- extra debug info needs to be expanded outside a function
- debug level is needed as macro parameter
- the expansion of %FILE% and %LINE% is wrong anyway. I stated this two
  weeks ago (patched myself).

You may say thats an really complex use case. It is, true. A full
fledged debug level stack oriented debugging system, which vanishes
completely from the code, if switched off. 

Complete source is available, if you do not believe it works.

The misunderstanding you mention is I spoke about the concept
of RTTI, however fpc calls it, typeof is part of this concept.
If you have variants you have a need for RTTI-concept too. 

The example with that small enumeration is not that bad, you think. The
overhead is what?, somehow 52 bytes data and maybe hundert of code. You
say its low, I say the example is very small too!

The same can be done with 0 bytes additional data and 0 bytes
additional code. In three ways:
- using compile time information (ugly build-in macro)
- using an macro
- keeping them in sync by hand (thats not the worst)
And thats the point.

It is a question of principal. If I write an program with really many
type definitions, for example 1000000 enumerated types and I do not
need the pseudo runtime information (because it is in real compile
time), why should I have it in my code?

It is a matter of cleanness and clarity.

Concepts are messed up this way.

Normally RTTI-concepts arise on top of inheritance-concept, which
arises on top of the object-concept. If you have variants-concept, there
too. But this is, I repeat myself, far from the base level of the
language, and I should not been forced to use it, because of the
absence of an base-concept, which macros are!
Again, in principal. If you break the rule, there have to be reasons.
Which? The ugliness of macros?

Indeed, messing around the concepts brings much problems, for example
interdependency of code where nobody would think, there is an
interdependency. Think of the impossibility to switch off rtti
generation (because of bugs, you state the problem, but not the reason).
This grows exponentially. One way to make the thing bigger and bigger,
up to the point, where nobody can do anything to solve a small problem
without understanding the whole thing.

I do not say change this, I agree, its not worth doing this, but it is
worth thinking about - keeping the conceptual view point right in your
And maybe a reason that macros are not that bad :)


More information about the fpc-devel mailing list