7

Why does \expandafter work with \uppercase, but not with \textbf?

Consider the following MWE:

\documentclass{article}

\begin{document}

\def\name{hello world}

\textbf\expandafter{\name}

\uppercase\expandafter{\name}

\end{document}

2 Answers2

7

Any TeX primitive that requires a ⟨general text⟩ has the same feature: in order to find the tokens that primitive should operate on, TeX performs macro expansion, ignoring space and \relax tokens as it goes, until it finds { (meaning either an explicit character token with category code 1 or a token \let to such character).

Besides \uppercase and \lowercase also

  • ⟨token variable⟩
  • \message and \errmessage
  • \write
  • \special
  • \mark and \marks (*)
  • \unexpanded (*)
  • \detokenize (*)
  • \scantokens (*)
  • \showtokens (*)
  • \expanded (*)

have the same property. The primitives marked with (*) aren't in Knuth TeX. Note that a ⟨general text⟩ must end with ⟨right brace⟩, which means an explicit character token of category 2. For instance

\def\foo{{foo}}
\uppercase\foo
\uppercase\relax\foo

will result in printing FOOFOO, but note the inner braces in the definition of \foo. With

\uppercase\expandafter{\name}

it's similar: since \expandafter is expandable, TeX performs the relevant action, which is to expand (one-level) the token following the next one (so { is jumped over and \name is expanded) and to vanish. Thus the main token list has

\uppercase{hello world}

and \uppercase can start its job: TeX looks up to the matching }, sends the tokens to the stomach, which will apply the \uccode equivalents and send back the result to the main token list; \uppercase and the braces have now disappeared and the result is

HELLO WORLD

Without \expandafter, the stomach would see \name to which it does nothing, because there's no character token hence it is sent back unchanged.

What's a ⟨token variable⟩? An example is \everymath, whereby

\everymath=\expandafter{\the\everymath ⟨other tokens⟩}

would append ⟨other tokens⟩ to the current contents of \everymath (the = is optional). Any ⟨token parameter⟩, \toks⟨number⟩ command and all tokens defined with \toksdef, usually via \newtoks, are instances of a ⟨token variable⟩; besides \everymath, there are other eight instances of ⟨token parameter⟩ listed on page 275 of the TeXbook.

To the contrary, \textbf is, from a practical point of view, a macro with one argument and so, by the rules of TeX about undelimited arguments,

\textbf\expandafter{\name}

would grab \expandafter as the argument and you have the same effect as

\textbf{\expandafter}{\name}

and the action of this \expandafter is just to expand an \else or a \fi a bit earlier than usual:

\ifmmode
  \nfss@text
  {\bfseries\expandafter}% <--- from #1
\else
  \hmode@bgroup
    \text@command{\expandafter}% <--- from #1
    \bfseries\check@icl\expandafter % <--- from #1
    \check@icr
    \expandafter\egroup
\fi

(as far as I can see, \text@command{\expandafter} would do nothing dangerous, but nothing useful either). Strictly speaking, \textbf has no argument, but its expansion is \protect\textbf• (the bullet denotes a space in the name) and it's \textbf• that takes one argument, but this is mostly irrelevant for the topic.

Note also that

\expandafter\uppercase\expandafter{\name}

works as well as

\expandafter\textbf\expandafter{\name}

but in the former the first \expandafter is redundant, while in the latter both are redundant, because \textbf essentially opens a group where \bfseries comes into force and the argument is typeset, as usual with macro expansion. Yes, \textbf does a bunch of other things as you see from the code above (replace the first three \expandafter tokens with \name), but I guess you used \textbf just by way of example. Indeed, the same applies to every macro taking one or more arguments.

egreg
  • 1,121,712
4

In this case the answer is just "given the internal implementation, the TeXbook states it would be".

First, \uppercase is a primitive TeX command, whose syntax is \uppercase ⟨general text⟩. So it will expand the following tokens in the input stream until it finds some { (any token with bgroup meaning). (TeXbook chapter 24 or https://tex.stackexchange.com/a/267413/250119)

In this case \expandafter is required because otherwise \uppercase will be applied on the token list \name instead of the token list hello world, which will not have the desired effect of capitalizing the text inside.

See also https://tex.stackexchange.com/a/199783/250119.

In the other case \textbf is defined as...

$ latexdef textbf

\textbf: macro:->\protect \textbf

\textbf : \long macro:#1->\ifmmode \nfss@text {\bfseries #1}\else \hmode@bgroup \text@command {#1}\bfseries \check@icl #1\check@icr \expandafter \egroup \fi

Given the rules that TeX use to grab undelimited argument, \expandafter will be grabbed as the argument and the following part is not made bold.

Remark: there may be some LaTeX commands whose implementation makes it so that \command \expandafter { ... } might just-happen to work properly (e.g. \exp_not:n), but unless it's explicitly documented as part of the command behavior, it's better to refrain from using it.

In this case simply using \textbf{\name} works. Alternative includes \expandafter\textbf\expandafter{\name}, \ExpandArgs{o}\textbf{\name} or \ExpandArgs{v}\textbf\name if it's necessary to pass the value of \name into the command.

user202729
  • 7,143