[Tex/LaTex] Multiple evaluation of a macro argument with side effects

macros

In C, preprocessor macros can have unexpected effects because their arguments can be evaluated multiple times. For example, the following code:

#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);

becomes:

int i = 5, j = ((i++)>(0) ? (i++) : (0));

and the variable i will have the value 7—not 6 as expected—because the macro's arguments are repeated in the macro definition.

Does LaTeX have similar issues? For example, what would happen in the following:

\newcommand{\foo}[1]{#1 #1}
\foo{\somethingwithsideeffects}

Would the side effects happen twice? If so, how can that be avoided? Can \edef be cleverly used to cause side effects to happen only once? Or \sbox (assuming the argument is something you want boxed)? Or maybe some way to automatically remove tokens that have side effects from #1?

Is this a problem in practice?

Best Answer

The side effect can occur in TeX as well. As far as I know there is no real way to avoid them. That is, if you produce something like you did in your example, there is no way to change \foo to accommodate that. Take the following example:

\documentclass{article}
\begin{document}
\gdef\switch{1}
\def\temp{\ifnum\switch=1\def\switch{0}x\else\def\switch{1}y\fi}
\def\foo#1{#1 #1}
\foo\temp
\end{document}

This will produce x y, because first the #1s in foo are replaced by their replacement text (\temp) and then those are expanded one at a time. That means \switch is changed before the second \temp is expanded. In this simple example grouping would help. If we changed the definition of \foo to \def\foo#1{{#1}{#1}} then it would print x x. However, this stops working when we \gdef instead of \def \switch inside of \temp. The problem is, if we can't modify \temp then we can't really do anything about that in \foo. So if you pass a macro with side effects to a macro that uses that argument more than once, it can lead to problems.

Related Question