5

\edef does expansion, but does not execute the commands. How in the following example make so that \foo will do assignment to \tmp at the moment of its call, not when it is defined? Why \foo produces 0F instead of 1F? Using \let in \bar works as needed. Also, calling \baz gives TeX capacity exceeded. Why?

\def\foo{F}
\def\bar{B}
\def\baz{Z}
\newcount\tmp
\newcount\N

\edef\foo{\tmp = \if aa \N \fi \the\tmp \foo}
\N=1
\foo

\let\oldbar = \bar
\def\bar{\tmp = \if aa \N \fi \the\tmp \oldbar}
\N=2
\bar

\expandafter\def\expandafter\baz\expandafter{\tmp = \if aa \N \fi \the\tmp \baz}
\N=3
%\baz

\bye
  • 1
    \edef\foo{\tmp = \if aa \N \fi \noexpand\the\tmp \foo} \N=1\foo – Steven B. Segletes Oct 22 '15 at 1:34
  • 1
    @StevenB.Segletes What if before \the\tmp we need to do \advance\tmp by 1? – Igor Liferenko Oct 22 '15 at 1:38
  • 2
    @StevenB.Segletes the \if aa \N \fi immediately expands in the \edef to <spacetoken>\N, thus we find at the start of the replacement text of \foo the assignment \tmp=<spacetoken><spacetoken>\N. No assignment is executed at the time of an \edef definition. The two spaces will be gobbled as they are a <filler>, at the time the \foo macro is expanded and the assignment is finally done. – user4686 Oct 22 '15 at 6:21
  • 2
    @StevenB.Segletes The count \tmp will then acquire the value stored in the count \N at the time \foo will be expanded. The \the\tmp in \foo on the other hand expands immediately to the value stored in \tmp at the time of \foo edef-definition. Idem for the \foo at the end of its own replacement text. – user4686 Oct 22 '15 at 6:21
  • 1
    in the \baz example the \expandafter's do nothing, because \tmp is a count, hence an unexpandable token. Thus we have \def\baz{stuff...\baz}. This definition can be done but when \baz is expanded naturally we end up in a never-finishing recursive loop, hence the TeX capacity exceeded. – user4686 Oct 22 '15 at 6:25
4

If you want that the definition of \foo is augmented by something at the beginning of the replacement text, the method is very standard:

\def\leftadd#1#2{% #1 is a parameterless macro, #2 a token list
  \toks0=\expandafter{#1}% store the expansion of #1
  \toks2={#2}% store the token list
  \edef#1{\the\toks2 \the\toks0}% redefine #1
}

Several other methods have been proposed, this is possibly the easiest to understand. It's based on the rule that tokens delivered by \the<toks register> are not expanded any more in an \edef.

With e-TeX extensions one can dispense with the token registers:

\def\leftadd#1#2{\edef#1{\unexpanded{#2}\unexpanded\expandafter{#1}}}

Now

\def\foo{F}
\leftadd\foo{\tmp = \if aa \N \fi \the\tmp}

is equivalent to having defined \foo by

\def\foo{\tmp = \if aa \N \fi \the\tmp F}

in the first place.


A token register free version:

\def\leftadd#1#2{\expandafter\leftaddaux\expandafter{#1}{#2}{#1}}
\def\leftaddaux#1#2#3{\def#3{#2#1}}
3

Upon EDIT, this addresses all the issues raised by the OP, regarding \foo and \baz. It also addresses subsequent issues raised by the OP in comments.

The \foo fix works by placing a \noexpand prior the \the\tmp in the \foo definition. And, in response to the OP's comment, it has no problem if \tmp must be advanced, as shown in the MWE.

The \baz fix involves expanding all the way out to \baz before setting the result in the new \baz definition. I placed a pile of stuff in \glob to simplify that process. Also EDITED to demonstrate \advance\tmp as part of \baz solution.

RE-EDITED to address other cases the OP asks in comments:

\painful is like \baz, but without using \glob.

\superbaz demonstrates the use of before and after \tmp values all at once.

\documentclass{article}
\begin{document}
\def\foo{F}
\def\bar{B}
\def\painful{W}
\def\baz{Z}
\newcount\tmp
\newcount\N

\edef\foo{\tmp = \if aa \N \fi \advance\tmp by 7 \noexpand\the\tmp \foo}
\N=1
\foo

\let\oldbar = \bar
\def\bar{\tmp = \if aa \N \fi \the\tmp \oldbar}
\N=2
\bar

\def\glob{\tmp = \if aa \N  \fi \advance\tmp by 2\noexpand\the\tmp}
\expandafter\def\expandafter\baz\expandafter{\expandafter\glob\baz}
\N=3
\baz

\expandafter\def\expandafter\painful\expandafter{\expandafter\tmp%
  \expandafter\expandafter\if\expandafter a\expandafter a%
  \expandafter\N\expandafter\fi\expandafter\the\expandafter\tmp\painful}
\N=4
\painful

\verb+\tmp+ is currently \the\tmp
\edef\superbaz{\the\tmp Z}

\def\glob{\tmp = \if aa \N  \fi \advance\tmp by 2\noexpand\the\tmp}
\expandafter\def\expandafter\superbaz\expandafter{\expandafter\glob\superbaz}
\N=5
\superbaz

%\bye
\end{document}

enter image description here

FINAL ADDENDUM:

In answer to the OP comment How to leave \the\tmp only in \superbaz and remove from \def\glob? (so that only 7Z will be printed). Also, how to do the same without \def\glob?

Beating a dead horse...

\documentclass{article}
\begin{document}
\newcount\tmp
\newcount\N

\def\ultimatebaz{\the\tmp Z}
\expandafter\def\expandafter\ultimatebaz\expandafter{%
  \expandafter\tmp\expandafter\expandafter\if\expandafter a\expandafter a%
  \expandafter\N\expandafter\fi\expandafter\advance\expandafter\tmp%
  \expandafter b\expandafter y\expandafter 2\expandafter\noexpand\ultimatebaz}
\N=5
\ultimatebaz\par
\end{document}

enter image description here

  • What does \noexpand do and why only \the\tmp is executed at the moment of definition? What if we put \the\tmp inside \def\foo? – Igor Liferenko Oct 22 '15 at 1:43
  • @IgorLiferenko The \noexpand prevents \the\tmp from being expanded during the \edef. Expanded, in this context, I am thinking, is equivalent to evaluation. – Steven B. Segletes Oct 22 '15 at 1:45
  • Is it possible to use \edef when \the\tmp is inside \def\foo? – Igor Liferenko Oct 22 '15 at 1:46
  • @IgorLiferenko I think my \baz fix addresses this final question. No? – Steven B. Segletes Oct 22 '15 at 1:51
  • Is it possible to do this not using \def\glob? – Igor Liferenko Oct 22 '15 at 2:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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