# Are commands defined by \newcommand[.][.]{.} robust?

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
}
l.3103 \edef\x{\cmd{1}}

? x


• I thought it is not and that is why there is \DeclareRobustCommand which has the same parameter syntax as \newcommand. – bodo Jun 19 '12 at 7:35

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.

The concepts of "fragility" and "robustness" are proper of LaTeX; a robust command is one that survives being in the replacement text for \protected@edef or \protected@write. It has nothing to do with surviving \edef or \write.

For example, after

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


something like

\edef\baz{\foo[x]}


will fail with

! Argument of \reserved@a has an extra }


Conversely, \protected@edef\baz{\foo[x]} will assign \baz the meaning

\protect \foo  [x]


(notice the two spaces after \foo). If we do instead

\newcommand\foo[1][bar]{...}
\protected@edef\baz{\foo[x]}


the meaning of \baz will be

\protect \foo [x]



Of course, \protected gives a robustness of a superior type, because a command defined with \protected\def will even survive \edef. But it's another story.

How does it work? When \newcommand\foo[1][bar]{...} is executed, LaTeX actually does

\def\foo{\@protected@testopt \foo \\foo {bar}}


and

\expandafter\def\csname\string\foo\endcsname[#1]{...}


which is very similar to the LaTeX2.09 way

\def\foo{\@testopt\@foo{bar}}
\def\@foo[#1]{...}


but has \@protected@testopt which is, essentially "if \protect equals \relax, then execute \@testopt\\foo, otherwise output \protect\foo". There's a small complication for taking care of "control symbols" such as \?, but this is pretty much the truth.

• So there is a difference in robustness between \newcommand with and without an optional argument? Is the one with the optional argument made robust in order to protect the default value? – bodo Jun 19 '12 at 8:33
• @canaaerus Protecting commands having an optional argument is necessary (actually something could be done, as proved in xparse, but it's quite a delicate feature). Protecting "normal" commands is usually undesirable: otherwise \write operations would never record current information such as the page or section number. – egreg Jun 19 '12 at 8:37
• @AhmedMusa I'm sure that if \protected had been available all the \protect thing would never have existed. But under the current state of affairs, commands having an optional argument defined with \newcommand are robust as far as LaTeX is concerned. – egreg Jun 19 '12 at 19:35
• It's pointless arguing with egreg, who has been teaching (or using) TeX since 1987, but for some of us who are new comers, we understand robustness the eTeX (and hence etoolbox's) way. Times change. I personally will prefer that robustness is an intrinsic property that doesn't depend on the current state or value of \protect or any command. Commands whose values are to be recorded in any file at runtime should, in this case, not be robustified in any way. – Ahmed Musa Jun 19 '12 at 19:39
• My view is that if eTeX was available in the 1980s, Leslie Lamport would probably have preferred \protected to \@protected@testopt. egreg has responded to this above. – Ahmed Musa Jun 19 '12 at 19:40

Such macros use the protect mechanism of LaTeX and will only work in a \protected@edef and other LaTeX macros, e.g. the aux-file writing macros, which set \protect accordantly. They are not meant to work in a general expanding context like \edef or a normal \write.

If you need to define a robust LaTeX macro with optional argument use the core macro \DeclareRobustCommand or \newrobustcmd from the etoolbox package.

• The second paragraph is not correct. \DeclareRobustCommand creates commands which will not expand inside \protected@edef, but will still go wrong inside \edef. For that, you need the e-TeX mechanism. – Joseph Wright Jun 19 '12 at 7:51