7

I managed to extract from my code the following MnWE which shows the problem i encounter :

Example 1

\begin{document}
\newcommand{\createDATA}[1]{
  \xdef\DATA{}
  \newcommand{\test}[2][]{
    \xdef\DATA{\DATA args=##1 , ##2 }
  }
  \test[x]{\macom[x]{blabla}}
}
\newcommand{\macom}[2][q]{AAA}
\createDATA
\DATA
\end{document}

The compilation gives an error : ! Use of \\test doesn't match its definition. which I can't understand. On the other hand, notice that if in the definition of \createDATA I replace \macom by a command without optional argument, then it works :

Example 2

\begin{document}
\newcommand{\createDATA}[1]{
  \xdef\DATA{}
  \newcommand{\test}[2][]{
    \xdef\DATA{\DATA args=##1 , ##2 }
  }
  \test[x]{\macomm{blabla}}
}
\newcommand{\macomm}[1]{BBB}
\createDATA
\DATA
\end{document}

It is very mysterious to me...

2
  • It's quite hard to understand what you're trying to achieve. But the problem is using a command with optional argument inside an \xdef. The error message is not quite informative, however.
    – egreg
    Commented Jun 18, 2012 at 17:59
  • 1
    This is the problem with minimal examples ... they sometimes have not meaning. This one just illustrates a problem, that i encounter in my code (which has a meaning!) Commented Jun 18, 2012 at 18:03

1 Answer 1

7

You are trying to \edef (\xdef = \global\edef) the macro \macom. However, as \macom is a command with an optional argument, this cannot be done safely. You need to either not do an \edef, use the LaTeX protected mechanism:

\documentclass{article}
\begin{document}
\makeatletter
\newcommand{\createDATA}[1]{%
  \xdef\DATA{}%
  \newcommand{\test}[2][]{%
    \protected@xdef\DATA{\DATA args=##1 , ##2 }%
  }%
  \test[x]{\macom[x]{blabla}}%
}
\makeatother
\newcommand{\macom}[2][q]{AAA}
\createDATA
\DATA
\end{document}

or make \macrom engine robust using the e-TeX extensions, for example

\documentclass{article}
\usepackage{etoolbox}
\begin{document}
\newcommand{\createDATA}[1]{%
  \xdef\DATA{}%
  \newcommand{\test}[2][]{%
    \xdef\DATA{\DATA args=##1 , ##2 }%
  }%
  \test[x]{\macom[x]{blabla}}%
}
\newrobustcmd{\macom}[2][q]{AAA}
\createDATA
\DATA
\end{document}

(By the way, you have a lot of extraneous spaces in your commands: I've added % to kill line ends and deal with these.)

For more on what robust, protected and 'fragile' means, see What is the difference between Fragile and Robust commands?


The reason that you cannot \edef a command with optional arguments is that these are picked up using the TeX primitive \futurelet. This performs an assignment, and assignments are not expandable. On the other hand, grabbing a mandatory argument does not require any tricks, so it is expandable.

[It's a bit more complex than that, as there are ways of expandably testing for optional arguments. These are more restrictive than the non-expandable approach, and the LaTeX2e kernel therefore goes with comprehensive-but-non-expandable. For pre-constructed methods for both expandable and non-expandable optional argument grabbing, with automatically robust functions and lots of additional cleverness, see the LaTeX3 xparse module.]

8
  • As egreg has commented on the question, I have no idea why there is an \edef being used here, hence saying that one (perhaps the most obvious) option is to simply avoid it entirely.
    – Joseph Wright
    Commented Jun 18, 2012 at 18:00
  • Could you please explain why one can not safely \edef a command with optional argument, but can do it without optional argument. Commented Jun 18, 2012 at 18:01
  • @nicolasroy No optional argument is a necessary condition for a macro to be safe in an \edef. Not sufficient. To be safe it must expand to unexpandable tokens without any intervening assignment. It's also important to note that the expansions are "all the way down".
    – egreg
    Commented Jun 18, 2012 at 18:06
  • Thanks a lot for the hints. Nevertheless, I don't understand your solution 1 : i thought that \protected@xdef would have a special effect (preventing expansion) on macro which are preceded by \protected in the edef, or defined with \protected. Did i miss something ? Commented Jun 18, 2012 at 18:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .