macro FAQ

Doug Tolton dtolton at yahoo.com
Sun Aug 24 03:15:31 EDT 2003


Jacek Generowicz <jacek.generowicz at cern.ch> wrote in message news:<tyfbruf998w.fsf at lxplus014.cern.ch>...
> > Macros can modify other code to make it fit the problem better,
> 
> What do you mean by "other" code? Macros modify the code that is
> passed to them as an argument, transforming it before the compiler
> gets to see it. I get the impression that you believe that macros can
> somehow modify code from other parts of the program. They can't.
> 
> Ultimately, macros just save you a lot of typing of source code. (And
> thereby save you a lot of bugs.) If you can't type it as soure code,
> then a macro can't do it.
> 
> > while functions only use other code but make no modifications.
> 
> This only strengthens the above suspicion, but I'm not really sure
> what you mean, here.
> 
> > This makes them very powerful but means that understanding a section
> > of code requires also knowing about any macros which might use the
> > code.
> 
> What do you mean by "macros using code" ?
> 
> The macros are part of the code, just like functions are. To
> understand the code, you must understand what the macros and functions
> do.
> 
> > In an extreme case which wouldn't be used in real projects, every *
> > could be replaced with a +.
> 
> This almost completely convinces me that you are very confused about
> what macros can achieve.
> 
> Either, you are suggesting that one might write a macro which replaces
> every * operator with a + operator, and then pass _the entire source
> code_ of a project to it (possible, but patently absurd); or you are
> suggesting that it is possible to write a macro "over here" which,
> somehow, surreptitiously modifies existing source code "over there".
> 
> a) Macros cannot do the latter.
> 
> b) You can achieve something very similar in Python, by re-binding
>    attributes of __builtins__.
> 
> Think of the point of macros in another way. The point is _not_ to
> take existing source code, and to change it. The point is to take
> something that is not (necessarily) valid source code, and turn it
> into valid source code, before the compiler gets to see it. Why?
> Because this allows you to create a shorthand notation, and use macros
> to expand it to real code. Think in terms of encoding design patterns.
> 

I think Jacek has made an extremely good point here, and I want to
follow up on it to determine if everyone has a clear understanding of
what macros are and are not.  Following I have outlined a series of
questions an answers to attempt to illuminate the issue.  Please
suggest any clarifications or distinctions that need to be made.  Also
note that the examples presented are purposefully trivial and could in
many instances be accomplished other ways, however I am presenting
these examples in order to provide a meaningful context to proceed
from.

Question: What are Macros?

Answer: Macros are an advanced templating system that allow dynamic
evaluation of code during run time.  Essentially Macros allow you to
pass in some variables that are then expanded into valid Python syntax
which is then executed.

Question: Can't I accomplish this same functionality via string
parsing and eval?

Answer: Eval will accept any valid Python expression and execute it. 
This is however regarded by many as a security hole.  Macros allow
this type of expressiveness while limiting many of the security risks.
 With a Macro you can more specifically control what types of actions
are permissible.

Question: I have some existing modules, if I import a macro from
someone else, could the macro make my existing code perform in
unexpected ways?

Answer: No.  A macro doesn't modify existing code, in order to invoke
a macro it must be called just like a function call.  So a Macro
couldn't alter the functionality of existing code any more than a
function could.  The only way to accomplish such a feat would be to
manually open each file and parse through them and re-evaluate them. 
This type of functionality is not what macros are about any more than
a function call would be.

Question: How would Macros work in practice?

Answer: Here is a trivial example macro to start with:

def HelloFunc(message):
      print "%s\n" % (message)

defmacro uselessmacro(message):
      macroexpansion = "HelloFunc(%s)" % (message)

defmacro callfunc(funcname, message):
      macroexpansion = """
               calllog = open("/var/log/functions.log", "a")
               calllog.write("%(funcname)s was called.\n")
               calllog.flush()
               calllog.close()
               %(funcname)s(%(message)s)
         """ % locals()

if __name__ == "__main__":
      uselessmacro("Hello World")
      callfunc("HelloFunc", "Hello World")

# Note, Jacek's method of using indentation is an interesting
alternative to calling them as a
# function.

# Second note, this textarea box does not have a compiler, so please
forgive any syntax errors :)

uselessmacro simply passes it's arguments through to HelloFunc
undisturbed
callfunc logs all calls to a function before evaluating the function

You could clearly accomplish this functionality using other means,
however I have used such a trivial example in order to illustrate
several points:

1) Macros once they are defined would most likely be invoked the same
way any other function call would be or represented as a block of
code.

2) Macros taken in isolation would not allow any strange changes to
the language to be made (eg changing all *'s to +'s, or changing the
behavior of existing classes - metaclasses, builtins and magic methods
are required for this)

3) Understanding a macro's behavior is typically easy for someone
familiar with Python's syntax and constructs.  In otherwords a Macro
allows you to encapsulate commonly used idioms into a cleaner syntax,
but would not allow you to alter the behavior of the language itself.

My examples are barely touching the surface of what is possible with
macros, but I wanted to start with some simple examples in order to
give everyone some solid examples of what Macros are, and what Macros
are not.




More information about the Python-list mailing list