The real answer is not to *always* protect macros that perform assignments, but the cases where you wouldn't want to do so are so special that it will be obvious to you the day you are in such a case. Let's consider a simple example:
```
\newif\iffoo
\newcommand{\mymacro}{%
\iffoo
\def\bar{a}%
\else
\def\bar{b}%
\fi
}
```
The two `\def\bar{…}` are assignments: they assign to the `\bar` macro. As such, they only work when TeX performs both expansion and execution. For instance, in an expansion-only context, processing `\def\bar{a}` does not assign anything:
* it tries to expand `\def`, which doesn't expand unless you redefined it (i.e., quite an extreme situation);
* it tries to expand `\bar`, which may well “do something” that is clearly unwanted in the code of `\mymacro` (it's already easy to see a big problem here: if what comes out of this expansion-only processing is further executed-with-interleaved-expansion by TeX, then instead of `\def\bar{a}`, TeX will see `\def a{a}` or `\def b{a}`, which for sure won't work as intended);
* it tries to expand all other tokens too, however unless you severely messed with TeX, the braces and `a` are unexpandable tokens like `\def` (of course, if you made `a` active, it expands like a macro).
So, a macro like this one, that conditionally defines `\bar`, only works “as designed” (in the “obvious” way) when processed at a time where TeX does expansion *and* execution. This is the “normal“ course of action, but there are plenty of situations (“expansion-only contexts”) where only expansion occurs: inside `\edef`, `\write`, when TeX reads a ⟨number⟩, ⟨dimen⟩ or ⟨glue⟩, etc. I wrote about these things before, please read e.g. [this answer](https://topanswers.xyz/tex?q=2007#a2255).
The macro `\mymacro` we have here is “meant” to define `\bar` as `a` when the `\iffoo` conditional is true (i.e., when it has been `\let`-equal to `\iftrue`) and as `b` otherwise. What happens if the macro is used in an expansion-only context?
For instance, let's say we use `\mymacro` in an argument that is used to provide typesetting material for the table of contents (a “moving argument” in the *LaTeX book* terminology). Such material is subject to `\write`, and `\write` expands its argument either immediately (when `\immediate` is used) or when the `\write` whatsit is shipped to a page, i.e. when TeX knows on which page it “lands” (this mechanism conveniently allows `\thepage` in the argument of `\write` to expand to the page number of typeset material next to the whatsit with no legal page break between them).
(A *whatsit* is a type of item that TeX puts in its horizontal, vertical or math lists, lists that are broken into paragraph lines and pages as typesetting goes. The whatsits come along with their neighbouring items which can be boxes, discretionary breaks, glue items, kerns, penalties, math-on or math-off items, etc. A non-`\immediate` `\write⟨number⟩{…}` appends a whatsit to the current list; when TeX ships out a page in which there is a box containing the whatsit, the recursive expansion of the token list denoted by `…` is written to the file which was assigned ⟨number⟩ by `\openout`.)
So, executing for instance `\write⟨number⟩{abc\mymacro def}` would write to the file opened under ⟨number⟩ the result of recursively expanding `abc\mymacro def`. The first expansion step (invisible as done internally by TeX) would yield this:
```
abc\iffoo
\def\bar{a}%
\else
\def\bar{b}%
\fi def
```
Then, still as part of the (possibly delayed) expansion performed by `\write`, and because TeX conditionals all work by expansion (one expansion step on `\iffoo` selects a branch, cf. the TeXbook), one would obtain either
```
abc\def\bar{a}\else \def\bar{b}\fi def
```
or
```
abc\def\bar{b}\fi def
```
Then, in either case, `\def` wouldn't expand, but `\bar` would unless it is unexpandable. This would go on until only unexpandable tokens remain (or tokens that were preceded by `\noexpand`, or that were inside `\unexpanded{…}`...).
Note: expanding the `\else` token would remove all the `\else … \fi` part, respecting nested conditionals, if any.
Which branch was taken in this scenario depends on whether `\iffoo` was true or false **at the time the braced token list read by `\write` was expanded**. When section titles are written to the .toc file, this occurs when the page containing the section title is shipped out; the material is written to the .toc file, and upon a later LaTeX run, it will be used to format the title *in the table of contents* (different place, different conditions!).
So, in this case, what gets written to the .toc file from the expansion of `\mymacro` by `\write` is not correct according to the “obvious intent” in the code of `\mymacro`, because the branch for the code that does formatting in the table of contents was selected based on the value of `\iffoo` at a completely different time: when the `\section` or `\chapter` or whatever did the `\write`, was written to a page—mid-document.
The general problem illustrated by this example is that when macro code is processed in an expansion-only context, the result depends on conditions at this time (`\iffoo` values, macro definitions) but if the macro code has things that can't work in an expansion-only context, these things, if they remain after the expansion-only process, will be processed *later* in a way that is likely not to make sense to the programmer, because the macro was written with the intent that everything would be expanded and executed in the same “run”.
By defining a `\protected` macro (using `\protected\def`, `\NewDocumentCommand`, `\cs_new_protected:Npn`, etc.), one ensures that it won't expand in expansion-only contexts. In our example modified to use `\protected\def\mymacro{…}`, the `\write` would keep `\mymacro` as is in the .toc file (followed by a space); `\mymacro` would be expanded later, at the right time: when the title is being typeset for the table of contents. This way, all its code—including conditionals and assignments—would work consistently.
**The key point is to ensure that all the macro code is processed consistently by TeX.** If one performs expansion-only on its code and interleaved expansion & execution later on the result, then what happens is most probably not what the programmer intended (except if that was done on purpose, which is why I said at the beginning of my answer that the “rule” does not cover 100% of the cases).
Fine print: *LuaTeX is an alien* and may perform assignments in expansion-only contexts. This is because, IIRC, `\directlua` “works” in such contexts (a single expansion step on `\directlua` causes it to execute all the Lua code in its argument); and because the Lua code can perform all kinds of assignments.
# Examples where the “rule” doesn't apply
As noted by Skillmon, standard macros `\rowcolor`, `\hline`, `\cline` and `\multicolumn` all contain material that is not expandable, yet must be defined as non-`\protected` in order to fulfill their duties. This is because:
- `\cline` and `\multicolumn` rely on the TeX primitive `\omit`;
- `\hline` and `\rowcolor` rely on the TeX primitive `\noalign`.
Building on these standard macros, we'll show how to implement a conditional `\rowcolor` by wrapping it in macro called `\rowFormat`, with an additional wrapper called `\onerow`. **The processing of `\rowFormat` and `\onerow` until they leave `\rowcolor` in the input stream must be expandable,** otherwise `\rowcolor` won't work (see below). Both wrappers must be non-`\protected` even though they use `\rowcolor`, which is not expandable material.
First some background: TeX has primitives `\halign` and `\valign` that are both used to typeset *alignments.* LaTeX's `tabular` and `array` environments both rely on `\halign`, and as such are TeX alignments (`\valign` is more... exotic).
As described on p. 240 of the TeXbook, when TeX is at the beginning of an alignment row, it recursively expands tokens until it finds an unexpandable, non-space token. If this token is `\noalign`, special processing happens (`\noalign` inserts user-specified vertical material). Otherwise, TeX starts processing an entry (cell) by reading the begin-part of the current column template. The same process applies to `\omit`, except `\omit` is looked for at the beginning of each entry rather than of each row.
Now back to our macros: because they may eventually leave a `\noalign` token in the input stream and we want it to “work”, one must let `\rowcolor`, `\rowFormat` and `\onerow` expand while TeX performs the special scanning process described above at the beginning of an alignment row. If TeX finds an unexpandable, non-space token during this process, and this token is neither `\noalign` nor `\omit`, it starts the first entry of the current alignment row and at this point, `\noalign` can't work anymore. `\rowcolor` uses `\noalign`, therefore if it is too late for `\noalign`, it is too late for `\rowcolor`.
If, for instance, the `\rowFormat` macro shown below were defined as `\protected`, the `\rowFormat` token at the beginning of a row would end the special scanning process; this, in turn, would prevent the `\rowcolor` inside `\rowFormat` from working (one would get the dreaded “Misplaced `\noalign`” error).
Such non-`\protected` macros whose replacement text contains material that is not expandable, are often used to test specific conditions (which, with many conditionals, works perfectly in expansion-only contexts, therefore doesn't end the special scanning process) and leave material in the input stream that is possibly not expandable and may depend on the conditions that were evaluated. In the example below, this is the case for `\rowFormat{foo}`, which expands:
- to `\rowcolor{red!40}` if the LaTeX counter `foo` is negative;
- to the empty token list otherwise.
Expandable conditionals that can be used in the same way include `\if`, `\ifx`,`\ifcat`, `\ifnum`, `\ifdim` and all other TeX conditionals; some or all of the tests provided by the `datatool` package; `expl3` tests on booleans, integers and floating point numbers; tests defined with `\prg_new_conditional:Npnn`; and certainly many others.
```
\documentclass{article}
\usepackage[table]{xcolor}
\makeatletter
\newcommand*{\ifLessThan}[2]{%
\ifnum\value{#1}<#2 % <--- one space token here, not \relax!!
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\newcommand*{\rowFormat}[1]{%
%\protected\def\rowFormat#1{% <---- doesn't work: “Misplaced \noalign.”
\ifLessThan{#1}{0}%
{\rowcolor{red!40}}% “then” clause
{}% “else” clause
}
\makeatother
\newcounter{foo}
\begin{document}
\newcommand{\onerow}[1]{%
\rowFormat{foo}%
foo is $\thefoo$%
\stepcounter{foo}%
& #1%
}
\setcounter{foo}{-3}
\begin{tabular}{ll}
\onerow{bla} \\
\onerow{pouet} \\
\onerow{This is the Way.} \\
\onerow{Yay!} \\
\onerow{Scrontch.} \\
\onerow{Paf!} \\
\onerow{Plouf.}\setcounter{foo}{-20}\\
\rowFormat{foo}foo is $\thefoo$ & The End.
\end{tabular}
\end{document}
```
![image.png](/image?hash=0f0a4c92a31de11d1b30ac8d5a126da9cd22918760ad4823340df93822ba81f2)
# Don't confuse `\protected` with `\protect`
`\protected` is a TeX primitive that appeared in e-TeX and is present in all current engines (not in Knuth's TeX).
In contrast, `\protect` is a macro defined by LaTeX; it does not require the e-TeX extensions, has a definition that varies depending on what LaTeX is doing, and is used in quite a different way.
## A glimpse on the `\protect` mechanism
Like `\protected`, `\protect` can be used to prevent unwanted expansion of tokens written by LaTeX to the .toc file, but note the conditions:
- `\protect` does *not* work in the general case of `\write`, `\edef`, TeX's scan-for-`\noalign`-or-`\omit`-while-expanding processes in alignments, etc.;
- `\protect` applies to particular *uses* of a macro, not to how it is defined.
How this works is not quite straightforward. LaTeX uses `\protected@write` to write to the .toc file. If users have a `\mymacro` that is fragile (neither `\protected` nor defined with LaTeX's `\DeclareRobustCommand` or similar) and that they need in a “moving argument”, they can use `\protect\mymacro` in the argument. `\protected@write` temporarily defines `\protect` as `\@unexpandable@protect`, which is:
```
\def\@unexpandable@protect{\noexpand\protect\noexpand}
```
With this temporary definition active, `\protected@write` performs an `\edef` (with `\thepage` `\let`-equal to `\relax` so that it doesn't expand yet) which stores the result of recursive expansion of `\write⟨number⟩{…}` in a `\reserved@a` macro. In the context of this `\edef`, `\protect\mymacro` expands to `\noexpand\protect\noexpand\mymacro`, which expands to `\protect\mymacro` and not further, due to how `\noexpand` works.
Then `\protected@write` uses `\reserved@a` and makes sure that if TeX is in vertical mode and in a place where page breaks must not happen, the `\write` from `\reserved@a` does not introduce an unwanted breakpoint.
The `\write` appends a whatsit to the current list for TeX typesetting, and this whatsit is eventually processed by the LaTeX `\output` routine. This routine is notoriously hairy, but as far as I understand it, when it ships out the page which causes the material stored in the whatsit to expand (including `\thepage`), `\protect` has the meaning of `\noexpand`.
As a consequence, what is written to the .toc file by the LaTeX `\output` routine is simply `\mymacro␣`, which is perfect for typesetting in the table of contents.
Note: in “normal” typesetting conditions, `\protect` has the meaning of `\relax`.