[Tex/LaTex] Are commands defined by \newcommand[.][.]{.} robust

latex-basemacrosoptional arguments

This question is from the comments at the foot of Abbreviations for AM, PM (small caps) for use within \textbf. Readers will get the remaining gist from there.

With

\newcommand\cmd[2][0]{\def\y{#1}}
\edef\x{\cmd{1}}

I get

{\edef}

\cmd ->\@protected@testopt \cmd \\cmd {0}

\@protected@testopt #1->\ifx \protect \@typeset@protect \expandafter \@testopt
\else \@x@protect #1\fi
#1<-\cmd
{\ifx}
{true}
{\expandafter}
{\else}

\@testopt #1#2->\kernel@ifnextchar [{#1}{#1[{#2}]}
#1<-\\cmd
#2<-0

\kernel@ifnextchar #1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reser
ved@b {#3}\futurelet \@let@token \@ifnch
#1<-[
#2<-\\cmd
#3<-\\cmd [{0}]

\reserved@a #11#2{->\expandafter \def \expandafter \\cmd \reserved@b #11{
! Argument of \reserved@a has an extra }.
<inserted text>
                \par
<to be read again>
                   }
l.3103 \edef\x{\cmd{1}}

? x

Is that robustness? See also Is there a robust \renewcommand replacement?.

Best Answer

Using

\newcommand{\foo}[...][...]

creates a macro \foo which has definition

\@protected@testopt \foo \\foo {...}

Inside a LaTeX 'protected expansion' command (\protected@edef, \protected@xdef, \protected@write), the definition of \@protected@testopt is altered such that no further expansion takes place, so that

\protected@edef\test{\foo}
\show\test

gives

> \test=macro:
->\protect \foo .

\DeclareRobustCommand works slightly differently, as

\DeclareRobustCommand{\foo}[...][...]

gives a definition

> \foo=macro:
->\protect \foo  .

where there is a space in the name of that internal macro: it's called '\foo '. Doing a 'protected expansion' here gives

> \test=macro:
->\protect \foo  .

i.e. the 'name with space' is retained. As this method adds \protect 'earlier' than the mechanism used by \newcommand, this is more robust at the cost of an additional cname.

Neither of these mechanisms will prevent expansion inside a plain \edef, \xdef or \write. For that, you need the e-TeX protected mechanism, which is wrapped up in a \newcommand-like way by \newrobustcmd from the etoolbox package. There, doing

\newrobustcmd{\foo}[...][...]

gives a definition

> \foo=\protected macro:
->\@testopt \\foo {...}.

This will never expand in an expansion context, as the engine is doing the protection.

Related Question