[Tex/LaTex] Macro to do nothing via a \def

expansionmacros

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:

enter image description here

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}

Best Answer

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}
Related Question