# Error with \edef and inner \def,

I seem to lack understanding the combination of an \edef and the definition of a macro inside another definition. This is probably best shown with an example.

The following MWE (I know it is not really useful so minimal) does not work:

\documentclass{article}
\def\mymacro#1{%
\def\do##1{##1}%
#1%
}

\begin{document}
\edef\savedValue{\mymacro{argument}}%
savedValue: \savedValue
\end{document}


The error is in the \edef line and states Illegal parameter number in definition of \savedValue.

I thought that the \edef would expand \mymacro{argument}, which first expands \def\do##1{##1} to nothing leading to the output argument, which is then saved into \savedValue. Without the line \def\do##1{##1} this seems to work as explained, but with that line I get the mentioned error.

What is the problem here?

Using xparse's command does work

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\mymacro}{m}{%
\def\do##1{##1}%
#1%
}

\begin{document}
\edef\savedValue{\mymacro{argument}}%
savedValue: \savedValue
\end{document}


and gives the expected output:

What is the actual difference to using \def?

-

the \def operation is not expandable. In an \edef \def is simply a non-expandable token that stays unchanged. Similarly \mymacro ends up being defined by \protected\def so does not expand in an \edef.

\show\mymacro


shows

> \mymacro=\protected macro:
#1->\def \do ##1{##1}#1.

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\mymacro}{m}{%
\def\do##1{##1}%
#1%
}

\begin{document}
\edef\savedValue{\mymacro{argument}}%
savedValue: \savedValue
\end{document}


So there are no expandable tokens in the definition of \savedValue so the \edef is equivalent to \def in this case. \show\savedValue shows

   > \savedValue=macro:
->\mymacro {argument}.


Then when \savedValue is expanded it is equivalent to

\def\do#1{#1}argument


If you use \def rather than \protected\def then when you get to the \edef mymacro expands (but \def doesn't so it is the same as

\edef\savedValue{\mymacro{argument}}%


is

\edef\savedValue{\def\do##1{##1}argument}%


then it tries to expand \def but that is not expandable so it is left, then it tries to expand \do so you get the expansion of whatever random definition \do has at this point which happens to be

 \do=\noexpand.


and things go wrong....

-
Thanks for the explanations. Is there a standard trick to "remove" the inner \def. Maybe I am thinking to complicated but there seems to be much benefit it that were possible. –  MMM Sep 15 '12 at 19:09
No once you have an unprotected definition that includes def it is the classic latex "fragile command' and "\edef" is the classic "moving argument". The solution to that is to use \protect to prevent the macro expanding. etex \protected\def as used by the expl3 command and the classic latex \DeclareRobustCommand mechanism both set things up so the macro automatically does not expand in the moving argument to save using \protect explictly. Searching fro "fragile command in a moving argument" on this site or via google will reveal lots of hits with further information:-) –  David Carlisle Sep 15 '12 at 19:37

Another possibility to avoid the problems explained by David Carlisle is to completely avoid the \edef. The trick is to put the saving inside of the "called function". This is a bit similar to C, where a pointer to the allocated memory is given as the first argument to a function and is normally an input-output-parameter. This pattern can probably save a lot of trouble with LaTeX.

\documentclass{article}
\usepackage{etoolbox}
\def\mymacro#1#2{%
\def\do##1{##1}%
\csdef{#1}{#2}%
}

\begin{document}
\mymacro{savedValue}{argument}%
savedValue: \savedValue
\end{document}

-
What's \def\do##1{##1} supposed to do? –  egreg Sep 15 '12 at 22:34
Serving as the placeholder for an MWE. In reality it would be the definition of a more complex \do macro, which is used in a \forcsvlist call. –  MMM Sep 21 '12 at 20:41