Fangyi Zhou


Meta-Programming in LaTeX

Many researchers write paper in $\LaTeX$ because it provides a convenient macro system that makes typesetting maths equations easy (or difficult, when it doesn’t work).

One way to write papers in $\LaTeX$ is to use as few “advanced features” as possible, for a vanilla experience: no fancy packages, just use the minimal setup. Gradually, as the paper starts to grow long, you begin to think of adding some macros for things that are too long to type, for example:

\newcommand{\lCalc}{$\lambda$-calculus}
\newcommand{\pCalc}{$\pi$-calculus}
\newcommand{\myTool}{\textsc{MyTool}}

Using macros can help improve consistency in writing, and hopefully reduce a few keystrokes. However, some macros may be very similar, like the following:

\newcommand{\redx}{{\color{red} x}}
\newcommand{\redy}{{\color{red} y}}
\newcommand{\redz}{{\color{red} z}}

When you realise red is maybe no longer your favourite colour, and decide to change everything into blue. You may think about doing some refactor like this to make future changes easier:

\newcommand{\termcolour}{\color{red}}
\newcommand{\termx}{{\termcolour x}}
\newcommand{\termy}{{\termcolour y}}
\newcommand{\termz}{{\termcolour z}}

Then you may want to do the same for other syntactic categories, e.g. types, type variables, … and okay, maybe some automation is needed.

Meta-Programming?

The term meta-programming can be interpreted in many ways. In this context, we want to write a command (i.e. a macro) to generate other comamnds (i.e. macros). It is analogous to template programming in C++ or macro programming in C. Fortunately, $\LaTeX$ is perfectly capable of allowing users to make macros to create other macros, because EVERYTHING IS A MACRO 1.

So intuitively, we want to have something like:

\makeMacro{term}{x}

to expand into

\newcommand{\termx}{{\termcolour x}}

We are encounted with an immediate question: how do we create make a macro with a non-constant name?

Using \csname and \endcsname to create a control sequence

After some time googling around and consulting this TeX FAQ, I learnt these two $\TeX$ primitives for marking the beginning and the end of a control sequence (in other words, macro names). See also this nice article.

Therefore, we can do something like:

%%% !!! THIS DOES NOT WORK !!!
\newcommand{\makeMacro}[2]{%
  % #1 is the prefix, #2 is the variable
  \newcommand\csname #1#2\endcsname{%
  {\csname #1colour\endcsname #2}%
  }%
}

We manage to construct a control sequence for our output macro: #1#2 will be expanded into \termx when passing {term} and {x} as arguments. Moreover, the colouring macro will be generated by #1colour, which will be expanded into \termcolour.

A few important notes here:

  1. The \csname and \endcsname must not be enclosed in curly braces (for a reason unknown to me, let me know if you know why).
  2. Putting a space before \endcsname will actually consider space as part of the control sequence, so no extra space before \endcsname.

However, the snippet above won’t work — it will produce an informative error message:

! LaTeX Error: Command \csname already defined.
               Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...

l.13 \makeMacro{term}{x}

It seems that we are trying to define \csname, which is not what we want. A closer look at TeXFAQ reveals the missing ingredient: \expandafter.

Also, not sure where I can find a manual and check p.192

So we need to \expandafter

Intuitively, \expandafter delays the expansion of a macro. In our use case, we want the control sequence between \csname and \endcsname to be expanded first, then the expanded result can be used as an argument to \newcommand.

However, \expandafter is known to cause possible confusions, as shown in here, and here, as well as multiple questions on TeX StackExchange. For the sake of my own sanity, I decided not to divulge too much into details and take it at face value.

So this is the final result:

\newcommand{\makeMacro}[2]{%
  % #1 is the prefix, #2 is the variable
  \expandafter\newcommand\csname #1#2\endcsname{%
  {\csname #1colour\endcsname #2}%
  }%
}

Still, a Minor Caveat

However, there is minor caveat that commands invoked with \csname and \endcsname will default to \relax (i.e. noop) if that command is not defined. This may be tricky to debug, as things may fail silently leaving you puzzled why your colour does not appear. One way to address this issue is to test whether the command #1colour exists before invoking it, with the eTeX primitive \ifcsname.

So, for the extra mile:

\newcommand{\makeMacro}[2]{%
  % #1 is the prefix, #2 is the variable
  \expandafter\newcommand\csname #1#2\endcsname{%
    \ifcsname #1colour\endcsname
      {\csname #1colour\endcsname #2}%
    \else
      Missing colour macro for {#1}
    \fi
  }%
}

That’s it!

With some meta-programming, I managed to create the package magicvariables for an extended version of the example covered in this article, and the package atendofenv for adding a small custom symbol at the end of an environment.

I hope this article is helpful for creating you own macros!


  1. Maybe a bit exaggerating. ↩︎