6

Suppose we have the following short document

\documentclass{article}

\def\foo#1{\if#1XX\else not X\fi}

\edef\bar#1{\if#1XX\else not X\fi}

\begin{document}
foo: X = \foo{X}, Y = \foo{Y}

bar: X = \bar{X}, Y = \bar{Y}
\end{document}

which results in

foo: X = X, Y = not X
bar: X = not X, Y = not X

The first case is quite simple to understand, expansion of \foo happens at the time the macro is called, #1 is replaced by X or Y, and the \if is executed with either of these two characters.

What is not so clear is the result of \bar. I understand that the expansion of \if here happens at the time the macro is defined and thus the concrete value of #1 not yet available; TeX leaves "holes" for the parameters in the expanded replacement text to be filled in later when the macro is actually called. But to properly expand the \if here, some value for #1 is needed.

The parameter doesn't seem to be just left empty, otherwise \bar shouldn't give not X, because \if XX would always be true. They also don't seem to be \relaxed, as

\edef\baz#1{\ifx#1\relax yes\else no\fi}

always gives no.

Then what values are used for the parameters at the time of definition?

5

When TeX does \edef<macro><parameter text>{1<replacement text>}2 it sets aside the <macro> the replacement text and {1, then does full expansion to <replacement text> until finding the matching }2. Finally it does

\def<macro><parameter text>{<full expansion of the replacement text>}

The full expansion of \if#1XX\else not X\fi is not X, because # and 1 are different character tokens (by character code).

Thus your \edef becomes the same as

\def\bar#1{not X}

As another example,

\edef\rightbracestring{\string}}

is perfectly legal, even if it appears to have unbalanced braces, because when the expansion is being done, the first } has already been tokenized as }12 when encountered. This proves that TeX doesn't first absorb the whole <replacement text>, but performs expansion just like in normal circumstances, with the difference that the matching }2 stops the process and resumes the assignment.

  • That's interesting, I've always thought #1...#9 are considered a single token, just like control sequence names. Is that behavior, that the parameter text is expaned before the final brace is found, documented? I'm having trouble finding it in the TeXbook – siracusa Sep 29 '18 at 9:04
  • 1
    @siracusa That's a simplification good for the purpose of presenting the basics of macro definitions. As far as TeX is concerned, #1 is two tokens when examining a definition for storing it in memory. I'm afraid you have to peruse tex.web or perhaps the simpler TeX by topic, as the TeXbook is quite reserved on the topic. – egreg Sep 29 '18 at 19:30
5

I would say that it compares # with 1 hance always goes for the false branch. (Compares second test where it compares # with # and chooses true branch)

\edef\bar#1{\if#1#1 (TRUE)\else #1 (FALSE)\fi}

\show\bar


\edef\bar#1{\if##1 (TRUE)\else (FALSE)\fi}

\show\bar

\bye

Gives

> \bar=macro:
#1->#1 (FALSE).
l.3 \show\bar

> \bar=macro:
#1->1 (TRUE).
l.8 \show\bar
  • 1
    try also \edef\bar#1{\if###1 (TRUE)\else (FALSE)\fi}, \bar X. – user4686 Sep 28 '18 at 15:58
  • Yes, if one tries (with pdftex) \edef\bar#1{\unless\if#1XX\else not X\fi}, \show\bar will output that \bar is a macro doing #1->XX. – egreg Sep 28 '18 at 16:11
  • @egreg good test case indeed. – user4686 Sep 28 '18 at 16:16

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.