Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question
add comment

2 Answers 2

up vote 3 down vote accepted

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.

share|improve this answer
    
Thank you for your answer. Can \edef or \sbox be used to eliminate the multiple side effects? See my revised question. –  Richard Hansen Apr 8 '12 at 0:13
add comment

This is a common problem when dealing with float captions. For example, here's the definition of \@makecaption which is called by \caption (taken from article.cls):

\long\def\@makecaption#1#2{%
  \vskip\abovecaptionskip
  \sbox\@tempboxa{#1: #2}%
  \ifdim \wd\@tempboxa >\hsize
    #1: #2\par
  \else
    \global \@minipagefalse
    \hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
  \fi
  \vskip\belowcaptionskip}

The caption is set inside a box \@tempboxa, after which its tested for horizontal width. If it fits, then the original box \@tempboxa is set, otherwise it is re-evaluated. The re-evaluation is performed to switch from centred (the default) to paragraph-style alignment of the caption. So, any \label or counter-related entries should be used with caution (especially if there's a contents for the floats created as well). Here's a small example:

enter image description here

\documentclass{article}
\newcounter{myitem}
\newcommand{\mynewitem}{\addtocounter{myitem}{1}I-\themyitem}
\begin{document}
\begin{figure}[ht]
  \centering\rule{150pt}{\baselineskip}
  \caption{This is \mynewitem.}
\end{figure}
\begin{figure}[ht]
  \centering\rule{150pt}{\baselineskip}
  \caption{This is \mynewitem\ together with a lengthy caption that stretches more than one line.}
\end{figure}
\end{document}

Resolutions to these problems are sometimes provided by manual work-around (which may vary on a case-by-case basis), or perhaps a package. Most solutions are provided by going back to the source and trying to understand the root of the problem, which invariably provide hints to possible work-arounds.

On a side-note. An interesting example of TeX's capability to be different from a programming language is presenting in David's answer to How do you swap the commands for two symbols?, suggesting that it's not always necessary to use a intermediate variable.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.