Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?.

share|improve this question
    
I thought it is not and that is why there is \DeclareRobustCommand which has the same parameter syntax as \newcommand. –  canaaerus Jun 19 '12 at 7:35
add comment

3 Answers

up vote 5 down vote accepted

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.

share|improve this answer
add comment

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]

(only one space after \foo). The robustifying method is different but equally effective. It must be noted that the robustifying is not applied when \newcommand is in its simple form \newcommand\foo[n]{...}.

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.

share|improve this answer
    
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? –  canaaerus Jun 19 '12 at 8:33
1  
@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
add comment

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.

share|improve this answer
2  
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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.