Checking For Empty Macro Arguments In Plain Tex

Detecting Empty Macro Arguments

When defining macros in plain TeX, it is often necessary to check if macro arguments are empty before attempting to operate on them. Empty arguments can cause unexpected behavior or errors if not handled properly. This article explains various methods for detecting empty arguments and how to avoid common pitfalls.

Why Check for Empty Arguments?

There are several key reasons for checking whether a macro argument is empty:

  • Applying operations to empty arguments can produce confusing behavior or errors:
    • Attempting math on an empty argument will yield an error
    • Formatting an empty argument can produce extra spaces or unusual output
  • Checks allow macros to handle missing arguments gracefully via conditionals
  • Checks make macros more robust and reusable
  • Detecting emptiness enables providing default values as needed

In short, checking for emptiness helps make macros more reliable and adaptable across use cases. Without checks, risk of unintended behavior increases.

How TeX Handles Empty Arguments

Before learning detection methods, understanding how TeX represents empty macro arguments is useful:

  • Formal arguments without passed content are not null but rather the next unexpanded input token.
  • This phantom "blank" token contains no printable content but behaves like any other token.
  • Testing if this blank token equals another token allows detecting empty arguments.

In essence, TeX norally passes an empty "placeholder" object rather than null when no physical argument content exists. This subtle behavior enables empty argument checks.

Built-in Methods for Checking Arguments

TeX provides several primitive commands for checking if an argument is blank:

\ifx
Compares if two tokens are identical
\ifeof
Checks if token is the end of file marker
\ifodd
Detects if token has odd categorical code

These core conditional commands can reliably detect an empty argument. However, some methods are more straightforward than others.

\ifx Comparison to Blank Token

One of the most common techniques is using \ifx to compare the argument to a blank placeholder token:


\def\check#1{\ifx#1\empty ... \else ... \fi}

This leverages TeX's underlying representation of empty arguments as a typeless blank token. If the argument #1 matches \empty syntactically, then it must be empty.

A limitation, however, is that \ifx compares the actual input tokens. This means it cannot detect expanded arguments that have blank content. For robustness, \ifx checking should usually be coupled with other tests.

Comparing Argument to \empty Token

A similar approach is comparing directly against TeX's \empty keyword using \ifx:


\def\check#1{\ifx#1\empty ... \else ... \fi} 

This achieves the same effect but arguably expresses the intent better by using TeX's designated empty marker.

Checking Argument Length with \length

A complementary approach is checking the number of tokens in the argument using \length:


\newcount\arglen
\def\check#1{\arglen=\length#1\relax 
             \ifnum\arglen=0 ... \else ... \fi}

This avoids issues with expanded arguments. However, \length is slower as it iterates through the tokens individually.

Example Macros Using Argument Checks

Here are some examples of macros using empty argument detection:

Version with default value


\def\foobar#1{\ifx#1\empty 
             \def\arg{default}\else
             \def\arg{#1}\fi
      \arg}

If argument is empty, \arg gets set to a default string. Otherwise argument is stored.

Version avoiding math error


\def\calc#1{\ifx#1\empty
            \errmessage{Argument cannot be empty!}%
       \else
            $ (#1) * (#1) $
       \fi}

If empty argument, throw understandable error to avoid confusing math error.

Version expanding before length check

  
\def\printargs#1{{\edef\temp{#1}}\length\temp=\z@
                 \ifodd\length\temp
                      \errmessage{No arguments given!}%
                  \else 
                      \temp
                  \fi}

\edef first fully expands #1 then \length checks if expanded argument empty. Robust across argument expansion states.

Custom Argument Checking with \meaning

A more advanced method is using \meaning to get a token's internal name then testing against the expected name for an empty placeholder:


\def\check#1{\def\argtype{\meaning#1}\ifx\argtype\space token 
                 ... \else ... \fi}

This leverages TeX's underlying categorization of tokens by type. \space tokens have the categorical name "blank".

Downsides are \meaning statements render arguments unusable. Also \meaning output depends on engines (pdfTeX vs XeTeX vs LuaTeX).

When to Avoid Argument Checks

While often useful, explicitly checking arguments for empty content isn't always necessary:

  • Macros designed for only non-empty use. If macro should never receive empty arguments, avoid checks and handle bad usage as errors.
  • Fallthrough defaults desired. Some macros intentionally leverage blank argument behavior for flexible interfaces.
  • Performance critical code. Length and meaning checks marginally impact speed vs \ifx.

In such cases, relying on TeX's inherent behavior for empty arguments may suffice.

Alternatives to Explicit Checking

In some contexts, alternatives to direct empty checks may be preferable:

  • Set default values with \def rather than conditionals inside macros.
  • Check emptiness at time of macro call rather than inside definition.
  • Use e-TeX's \dimexpr and \numexpr instead of expandable calculations.

Finally, LuaTeX and ConTeXT offer additional functions like \instr that can implicitly handle empty arguments.

Choosing the most robust empty argument handling method depends greatly on the specific use case.

Leave a Reply

Your email address will not be published. Required fields are marked *