Re: Recent topics ( macros )

Steven D. Majewski (sdm7g@elvis.med.virginia.edu)
Thu, 27 Jan 1994 03:51:47 -0500

On Jan 26, 0:41, Tim Peters wrote:
( in response to Steve Miale's question: )
> > ...
> > How difficult would it be to incorporate a simple macro expander in
> > Python? I remember experimenting with calling the c preprocessor, and
> > it seemed to work most of the time.
>
> What uses do you have in mind? I've often wanted to expand teensy
> functions inline, but (A) couldn't figure out how to fool cpp into
> getting the indentation correct in context (& had the same problem with
> m4, of course), and (B) don't like wrestling with macro semantics for
> this purpose regardless.
>
> For #define'ing constants, or #include'ing files, I've usually ended up
> happier crafting a solution using Python modules and 'import' instead.
>
> if-macros-are-the-solution-what's-the-problem<heh-heh>?-ly y'rs - tim
>

If the "problem" is effeciency and wanting to have in-line functions:

Some versions of FORTH do inline expansion of the threaded code rather
that the source code. This would probably work on Python's compiled
byte-code, also.

example:
a FORTH word defined as:

: FUNC FUNX FUNY FUNZ ;

would get compiled into a dictionary entry for the word FUNC,
a Code Field Address for DOCOL - the "Colon" or threaded code
interpreter, and tokens or addresses for FUNX, FUNY and FUNZ.

An optimizer can be run on the word that will expand the
code for FUNX, etc. in line, and if desired, recursively
until FUNC contains machine code rather than threaded code.

The Python interpreter has no knowledge of the representation
of the C-coded and compiled builtin's, so it may not be able
to expand to that level, but I think an inline code expander
/ optimizer that works on compiled objects might be possible.

Of course, you would only want to run this expander on finished
applications - if you made any changes in the underlying code,
the old methods would be inlined.

More ambitious would be to add a Self-like optimizer - my
rough understanding of how it works is: the "typical case"
method is guessed and full dynamic lookup is skipped -
except that the called method, if called with the wrong
argument then calls the dynamic dispatcher. ( The idea
is similar to Tim's use of exception handling to avoid
extra dictionary lookups. ) So if "a = a + b" was last
used in the context of a and b being strings, then the
next time that code executes, string.__add__ ( or
whatever ) is called without -- if IT gets a number
this time, it raises an exception that does the full
method lookup ( and possibly replace the default method. )

However, **I** have no idea if this is possible to
implement within Python, of if it is, whether it gains
as much. I suspect that Python's dynamic scoping would
get in the way ( and I recall that some of the pre-Scheme
and pre-Common-Lisp versions of Lisp that used dynamic
scoping on INTERPRETING code, and static scoping on
COMPILED code were awfully confusing just because of
the different behaviour of compiled or interpreted code!)

On the more general topic of Macro's :
Again, comp.lang.dylan was discussing Macro's in the thread
about a LISP-like syntax for Dylan vs. an algol/C [or Python?]
like syntax. [ Apple has confirmed that the algebraic/infix
notation will be the standard one with the Lisp syntax being
optional. A Not-unanimously-popular decision, but one that
shows that they are targeting the language for the non-Lispers. ]
The usual pro-parentheses argument is that the identical
representation for code and data makes it easy to write
program transformation programs like macros. The counter
argument was that it was the INTERNAL representation
( S-expressions ) that were operated on by macros, NOT
the source code text ( although that leaves out that the
Lisp Reader is able to be modified so that the print
representation of a new data type is recognized by the
reader. )

Anyway, back to Python: lacking "#ifdef DEBUG", I have
sometimes just defined two versions of a routine -
the "debug" version and the "production" version,
and just swapped the one in use with:
"function = debug_function"
but it DOES take more manual labor with the editor to
do this. But this would also seem to be something
that a complied code expander could handle -- you
could tell it to remove everything that followed
the CODE equivalent of "if DEBUG :" - but this
wouldn't be very automatic. Probably what Python
would need to make dead code elimination the typical
action of the compiler would be some sort of
"CONSTANT" declaration - to say use this value now -
don't insert dynamic lookup code. ( but then I
seem to remember that Python does some strange
local lookup of constants ? ) Def-ing a function
or method as a Constant could also be an indicator
that that function was allowed to be inlined.

- Just the 3:30 AM ravings of someone who's been
sleeping off the Flu all afternoon - Steve

- Steve Majewski (804-982-0831) <sdm7g@Virginia.EDU>
- UVA Department of Molecular Physiology and Biological Physics