Macro to do nothing via a \def

I have encountered another expansion issue and have narrowed it down to this simple test case of a macro that does nothing, well at least it tries to do nothing, but is not all that successful.

If I declare this macro as:

\newcommand*{\DoNothingA}[1]{#1}%


This works great, no surprises there.

However, if this macros is defined as follows:

\newcommand*{\DoNothingB}[1]{%
\def\Temp{#1}%
\Temp%
}%


then, this has problems where there is an attempt to use this in an \edef.

Output:

Note that the MWE below yields a compile error for the last step, so you need to hit <RETURN> to skip past it to see the output (or comment out the last \edef, but then this won't show Question 2 below).

The MWE below yields the following:

The last line being especially curious as it produced foo 4, and was the result of:

\edef\NewTemp{\DoNothingA{foo 5}}
\NewTemp
\color{red}% Highlight problem output
\edef\NewTemp{\DoNothingB{foo 6}}
\NewTemp
\color{black}
~-- used \verb|\edef| to store output of macro


Questions:

1. What is the explanation of the expansion issue here?
2. How does the final output become foo 4 (foo 5 would have been easier to accept), if we skip past the compile error?
3. Since David Carlisle has been quoted as saying that "a few extra \expandafter cure all known ills" :-), what is the sequence of \expandafters needed in the last \edef to use macro \DoNothinB as defined here.
4. How can I adjust the \DoNothingB{} macro to use a temp variable and still work in the three cases in the MWE (preferrably without having to use any \expandafter trickery.

Code:

\documentclass{article}
\usepackage{xcolor}% To highlight problem output

\newcommand*{\DoNothingA}[1]{#1}% Does everything I want in all cases

\newcommand*{\DoNothingB}[1]{% Works mostly, except if used in a \edef
\def\Temp{#1}%
\Temp%
}%

\begin{document}
% These two work great.
\DoNothingA{foo 1}
\DoNothingB{foo 2}
-- used output of macro directly

% These two also work great.
\def\NewTemp{\DoNothingA{foo 3}}
\NewTemp
\def\NewTemp{\DoNothingB{foo 4}}
\NewTemp
~-- used \verb|\def| to store output of macro

\edef\NewTemp{\DoNothingA{foo 5}}
\NewTemp
\color{red}% Highlight problem output
\edef\NewTemp{\DoNothingB{foo 6}}
%\show\NewTemp% Excellent suggestion by David Carlisle yields: \def foo 4{foo 6}foo 4
\NewTemp
\color{black}
~-- used \verb|\edef| to store output of macro
% Why is the last output "foo 4" (after ignoring error)??
\end{document}

-

2 Answers

Short answer: You can't use assignments like \def or \edef inside expandable contexts like \edef because they are not expandable!

Long answer:
An \edef expands its content until only non-expandable tokens are left (note that text is not expandable). \def is an assignment and all assignments must be executed and are therefore not expandable. Your \DoNothingB actually does something: it defines \Temp!

Let me explain what happens on the following example:

\def\Temp{before}
% ...
\edef\NewTemp{\def\Temp{something}}


then the \edef tries to expand first \def which is not expandable and therefore stays at it is, then \temp which is expanded to before and then the rest: the tokens {, s, o, ..., g, and }, which are all not expandable either. Therefore you get \NewTemp as \def before{something} which will instruct TeX, once \NewTemp is expanded, i.e. used, to define b with the parameter text efore and the replacement text something. Because b is immutable (as long it is not declared an active character) you will get an error here.

In your example \Temp has been define to foo 4 in your fourth example, where you use \DoNothingB outside of an \edef. In the next usage inside of an \edef (\edef\NewTemp{\DoNothingB{foo 6}}) you get \def foo4{foo 6}foo4 for \NewTemp because both \Temp usage are expanded right then, which leads to the above mentioned error. The \def foo4{foo 6} is discarded as part of the error handling and then foo4 is typeset. If \Temp would be defined differently before the output would be accordantly.

A few \expandafters don't help you here because the order is not the issue here and \edef expands anyway everything continuously until only non-expandable tokens remain.

However, you might want to add some \noexpand direct before the \Temp macros inside \DoNothingB to protect them from premature expansion in the first \edef. This now doesn't work inside a \def. Normally you can use \protect with LaTeX's \protected@edef instead. Depending on the context \protect is either \relax (outside \protected@edef) or \@unexpandable@protect (inside \protected@edef) which is similar to \noexpand. For usage with \def you need to test this mode by yourself and add a \noexpand manually if inside edef.

The following code does this. Note that you need to replace all \edefs with \protected@edef for this to work. The normal \edef and other expanding contexts like \message or \write will not work.

\documentclass{article}
\usepackage{xcolor}% To highlight problem output

\newcommand*{\DoNothingA}[1]{#1}% Does everything I want in all cases

\makeatletter
\newcommand*{\DoNothingB}[1]{% Works mostly, except if used in a \edef
\ifx\protect\@unexpandable@protect
\def\noexpand\Temp{#1}%
\else
\def\Temp{#1}%
\fi
\protect\Temp%
}%
\makeatother

\begin{document}
% These two work great.
\DoNothingA{foo 1}
\DoNothingB{foo 2}
-- used output of macro directly

% These two also work great.
\def\NewTemp{\DoNothingA{foo 3}}
\NewTemp
\def\NewTemp{\DoNothingB{foo 4}}
\NewTemp
~-- used \verb|\def| to store output of macro

\edef\NewTemp{\DoNothingA{foo 5}}
\NewTemp
\color{red}% Highlight problem output
\makeatletter
\protected@edef\NewTemp{\DoNothingB{foo 6}}
\makeatother
\NewTemp
\color{black}
~-- used \verb|\edef| to store output of macro
% Why is the last output "foo 4" (after ignoring error)??
\end{document}

-
\newcommand*{\DoNothingA}[1]{#1}

\newcommand*{\DoNothingB}[1]{\def\Temp{#1}\Temp}

\begin{document}

\DoNothingA{foo 1}
\DoNothingB{foo 2}


According to the definitions this prints "foo 1" and "foo 2" and defines \Temp to expand to foo 2

\def\NewTemp{\DoNothingA{foo 3}}
\NewTemp


This defines \NewTemp to expand to \DoNothingA{foo 3}, so \NewTemp prints "foo 3"

\def\NewTemp{\DoNothingB{foo 4}}
\NewTemp


This does

\DoNothingB{foo 4}


which defines \Temp to expand to foo 4 and prints "foo 4"

\edef\NewTemp{\DoNothingA{foo 5}}
\NewTemp


Let's go slowly here. The \edef causes the expansion of \DoNothingA, which finds it argument and is replaced by its replacement text; all is eventually equivalent to saying

\def\NewTemp{foo 5}


Now the fun begins.

\edef\NewTemp{\DoNothingB{foo 6}}


Here \DoNothingB finds its argument and is replaced by

\def\Temp{foo 6}\Temp


but \edef is not satisfied and replaces both instances of \Temp by its replacement text, which is still foo 4 and so TeX executes the equivalent of

\def\NewTemp{\def foo4{foo 6}foo 4}


and now the call

\NewTemp


will try doing

\def foo4{foo 6}foo 4


The result is an error message: since no control sequence follows \def, TeX inserts \inaccessible and performs

\def\inaccessible foo4{foo 6}foo 4


which results in printing "foo 4" after having defined the \inaccessible control sequence.

So there are the answers to 1 and 2. The answers to 3 and 4 are easy: you can't perform an assignment during an \edef, with any number of \expandafters, because TeX doesn't perform assignments during expansion, but only at a later stage of processing. In summary: you can't change the meaning of a control sequence while doing an \edef.

Workaround

If you want to feed \DoNothingB in an \edef you have to decide what it's supposed to do in that case. If you simply want that it does nothing special with respect to being inside a \def then

\protected\def\Temp{} % initialization
\newcommand*\DoNothingB[1]{\protected\def\Temp{#1}\Temp}


might do; if you say

\edef\NewTemp{\DoNothingB{foo}}


this would expand \DoNothingB resulting in the token list

\protected\def\Temp{foo}\Temp


but now all tokens are unexpandable and so the \edef would be equivalent to

\def\NewTemp{\protected\def\Temp{foo}\Temp}


In case of \def\NewTemp{\DoNothingB{foo}} a call of \NewTemp would do the same as before after the first expansion step. Note that it's necessary to initialize \Temp to be a \protected macro, otherwise something like

\edef\NewTemp{\DoNothingB{foo}}


would result in an error message about "Undefined control sequence".

Of course, this is under the assumption that the argument to \DoNothingB is made of unexpandable tokens, as they wouldn't be protected against expansion.

-