Wednesday, September 23, 2009

Appending to a macro

On occasion, one wishes to modify an existing macro by appending additional text or macros. For a simple example, suppose we have a complicated macro \foo and what we'd like is to replace all instances of \foo by \foo bar&emdash;that is, the macro \foo followed by the three tokens "bar". Now, potentially, one could replace all instances of \foo with "\foo bar", but this isn't always feasible, especially if \foo is normally expanded by some other macro in a package or class file. A first attempt at a solution—which won't work— is to try
\def\foo{\foo bar}
This doesn't work for the obvious reason that while expanding \foo, it will expand \foo, which will expand \foo, and then that will expand... A second attempt which is more successful is to use \let along with a second, helper macro.
\def\foo{\fooHelper bar}
This works but seems inelegant in that you have to keep the \fooHelper macro around. Any changes made to it change \foo. What we really want is a way to expand \foo in the replacement text in our first attempt above. We can use the TeX primitive \expandafter for this. \expandafter is an expandable control sequence that causes the second macro that follows it to be expanded one "level." That is, \expandafter\a\b has the effect of expanding \b once and then expanding \a. For example
has the following expansion:
  • \expandafter\a\b
  • \a\c
  • A\c
  • AC
Since \expandafter is itself expandable, multiple \expandafters can be used completely alter the order of expansion. For our purposes, we need
\expandafter\def\expandafter\foo\expandafter{\foo bar}
This will expand \foo in the replacement text before making the new definition of \foo. The LaTeX kernel provides a \g@addto@macro that takes two arguments and globally appends its second argument to the first argument. That is, \g@addto@macro\foo{bar} globally performs the assignment we did above. This has the drawback that it can't be used inside a group where we want the definition to be local to that group. In a later post, I'll show how to add replacement text to places other than at the end.

1 comment:

  1. \def\aroundto#1#2#3{\toks0={#2}\toks1=\expandafter{#1}\toks2={#3}\edef#1{\the\toks0 \the\toks1 \the\toks2}}

    Now you can add to the beginning, as well.