3

If I have the following piece of code, everything compiles:

\documentclass{article}    
\newcommand{\mycmd}{
  \edef\tmpcmd{test} % No commands with arguments
  \tmpcmd
}

\begin{document}
\mycmd
\end{document}

But if it looks like this:

\documentclass{article}    
\newcommand{\mycmd}{
  \edef\tmpcmd{\textit{test}} % Has a command with argument
  \tmpcmd
}

\begin{document}
\mycmd
\end{document}

Then I get a weird error:

! Undefined control sequence.
\GenericError  ...                                
                                                #4  \errhelp \@err@     ...
l.9 \mycmd

Why is this?

gablin
  • 17,006
  • You can't even do \edef\tmpcmd{\textit{test}} outside of \mycmd, much less inside a macro. Some macros are just not expandable. – Steven B. Segletes Jun 25 '15 at 11:52
  • 2
    See e.g. http://tex.stackexchange.com/questions/5693/minimal-protectededef-example, http://tex.stackexchange.com/questions/4736/what-is-the-difference-between-fragile-and-robust-commands – Joseph Wright Jun 25 '15 at 12:01

2 Answers2

6

This issue isn't that the macro has an argument, but whether the argument is expandable. For example, this slight alteration of your MWE works fine, since \foo is expandable:

\documentclass{article}  
\newcommand{\mycmd}{%
  \edef\tmpcmd{\foo{test}}% Has a command with argument
  \tmpcmd
}
\newcommand\foo[1]{foo:#1:bar}
\begin{document}
\mycmd
\end{document}

enter image description here

The problem with the OP's MWE is that \textit is not fully expandable.

The \protected@edef macro can get one through many of these situations, and the links that Joseph mentions in his comment to the OP, which I repeat here for convenience, explain in intricate detail all the reasons why.

Minimal \protected@edef example

What is the difference between Fragile and Robust commands?

\documentclass{article}  
\makeatletter  
\newcommand{\mycmd}{%
  \protected@edef\tmpcmd{\textit{test}}% Has a command with argument
  \tmpcmd
}
\makeatother
\begin{document}
\mycmd
\end{document}

enter image description here

In addition to searching this site for "expandable", looking into the concepts of "fragile" and "robust" would also be instructive, as Gustavo notes.

  • 1
    Well, the reason why this works is that \textit is defined with \DeclareRobustCommand, isn't it? – GuM Jun 25 '15 at 12:06
1

\protected@edef (see Steven’s answer), however, won’t inihibit the expansion of commands not declared as robust, unless you explicitly \protect them inside the replacement text. The following, trivial alternative

\documentclass{article}  
\newcommand*{\mycmd}{%
  \edef\tmpcmd{\noexpand\textit{test}}%
  \tmpcmd
}

\begin{document}
\mycmd
\end{document}

is more general, probably neater, and has the additional advantage of sparing an infinitesimal amount of memory.

GuM
  • 21,558
  • Now I see where you were going with your comment. Nice. +1 – Steven B. Segletes Jun 25 '15 at 12:44
  • I beg to disagree: \protected@edef is the way to go. – egreg Jun 25 '15 at 12:47
  • @egreg: Would you please elaborate on your comment? – GuM Jun 25 '15 at 12:54
  • 1
    Look at the duplicate question http://tex.stackexchange.com/questions/252183/edef-together-with-microtype-generates-an-error and tell how you'd use \noexpand. – egreg Jun 25 '15 at 12:55
  • I’m afraid I can’t get at what you mean: referring to the example you mention, what’s wrong with \keyword[na\noexpand\"ive]? But I cannot initiate a discussion in the comments: are you willing to teach me something about this issue on chat? (If I can abuse your time, of course! :-) – GuM Jun 25 '15 at 13:11