Enter the void *

Bring your own switch

by Etienne Millon on June 5, 2014

Tagged as: .

TeX is a very primitive language. Everything is dynamic, even parsing. This explains in part why it’s so long to compile.

It also means that it’s very flexible : it’s possible to define your own control structures. Here is a small explanation of an implementation of a “switch” macro I made last year. It is released as part of my discotex library (a collection of macros, really).

We want to define a control structure that we can use in the following way:

\switch{what}{case1}{then1}
             {case2}{then2}
             {case3}{then3}
             {END}

Then, if what is equal to case1, the whole construct evaluates to then1, etc. This looks like a function with a variable number of arguments, but actually this is well adapted to how TeX works.

In TeX, control is provided through macros, i.e. rules to rewrite text. Suppose we want to do a macro that expands to “x and y”. LaTeX users are used to the following syntax:

\newcommand{\couple}[2]{#1 and #2}

But in TeX this is written:

\def\couple#1#2{#1 and #2}

Which roughly means that after reading \couple, TeX will read two strings1 and bind them to #1 and #2 in the body. So \couple{A}{B} is expanded to A and B.

Here comes the trick used for defining variadic functions: if more arguments are provided than the number of arguments at the definition point, the extra ones are kept at their place. If fewer arguments are provided, the strings after the call site will be used. So, one can look at TeX functions as just a system to pop strings from the calling site.

Using this, we can implement \switch:

These 3 points map well to the final TeX code.

To read the first case, we write a function with only two parameters. For string comparison we use \ifstrequal{a}{b}{t}{f}2 which expands to t if a and b are equal, or f otherwise. Note that \switch@next is the name of a function. In .sty files, it is possible to use @ in symbol names. It is a convention for private macros as they can not be directly used in .tex files.

\def\switch#1#2{
  \ifstrequal{#2}{END}{
    \errmessage{switch : case "#1" not found}
  }{
    \switch@next{#1}{#2}
  }
}

It is also used to do the actual comparison and the recursive call.

\def\switch@next#1#2#3{
  \ifstrequal{#1}{#2}
    {#3\switch@last}
    {
      \switch{#1}
    }
}

Then \switch@last is a simple recursive function which simulates a loop. Because the recursive call is done without an explicit parameter, it will keep on popping strings until finding END.

\def\switch@last#1{
  \ifstrequal{#1}{END}{}
  {\switch@last}
}

That’s it, the macro works. You can even try it!

I am not sure that I would like to write more complex control structures but this was useful to me both in writing it and using it. I hope that you enjoyed it!


  1. I am not sure that this is the correct denomination. For example it will read a string between curly braces, or a single character if they are omitted. In that case it also eats whitespace, which is why you need stuff like \xspace to prevent your macros from glueing string together.↩︎

  2. It is from the etoolbox package. How it works is an implementation detail here, though it would probably be interesting.↩︎