13

With

\edef\x{\ifnum0=0\else\fi}

being \relax and with

\def\y{\relax}

we see that \ifx\x\y is false. Why?

See also \ifcsname x\endcsname when it isn't apparent that \x was made \relax.

4
  • 2
    See also this related chat discussion. Apparently the special relax has a different definition than the normal one. May 26, 2012 at 11:26
  • On the other hand, \expandafter\ifx\x\relax is true. This works for all primitives that have a frozen version and therefore appear twice in the equivalence table. With LuaTeX, you can create additional copies of primitives using tex.enableprimitives, and they show the same behavior.
    – Philipp
    May 26, 2012 at 14:51
  • Generally speaking, \ifx only looks one level deep: it checks whether all tokens have the same indices into the equivalence table, but does not check whether they have the same meaning. The same works with \let\foo=\relax: Now \foo is a token with the meaning of \relax but a different name.
    – Philipp
    May 26, 2012 at 14:55
  • Does pdfTeX have something similar to tex.enableprimitives?
    – Ahmed Musa
    May 27, 2012 at 0:00

2 Answers 2

19

Let's look at the transcript of an interactive session with TeX.

> tex
This is TeX, Version 3.1415926 (TeX Live 2011)
**\relax

*\def\x{\relax}

*\edef\y{\ifnum0=0\fi}

*\show\x
> \x=macro:
->\relax .
<*> \show\x

?      

*\show\y
> \y=macro:
->\relax .
<*> \show\y

? 

*\ifx\x\y\message{EQUAL}\else\message{UNEQUAL}\fi
UNEQUAL

*\edef\z{\ifnum0=0 \fi}

*\show\z
> \z=macro:
->.
<*> \show\z

? 

*\bye
No pages of output.
Transcript written on texput.log.

Why aren't \x and \y equivalent? And why aren't \y and \z equivalent in the first place?

The conditionals

\ifnum0=0\fi

or

\ifnum0=0\else\fi

are pretty much the same and the fact that \y becomes nonempty stems down from another precaution that TeX takes against premature expansion.

When TeX is looking for a <number> it expands tokens as it goes. But in this case it finds a \fi or an \else that matches the \ifnum while the search for the second number to test is still unfinished. Were it to expand the \fi or \else everything bad might happen. So, in this cases, TeX inserts a "safe" token that it represents on the terminal with \relax but is in fact not the same \relax that we know and are allowed to use. For instance, you can't redefine this token:

This is TeX, Version 3.1415926 (TeX Live 2011)
**\relax

*\edef\x{\ifnum0=0\fi}

*\expandafter\def\x{Something}
! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
<*> \expandafter\def\x
                      {Something}

One is not allowed to feed the "frozen relax" token to \def, as it is evident from the above interactive session.

The problem does not show with

\edef\z{\ifnum0=0 \fi}

because the lookup for the <number> is terminated by the space token (which is then ignored). Therefore this is just a complicated way to say

\def\z{}

Note. With \edef\Z{\ifnum0=1\else\fi} or \edef\Z{\ifnum0=1\fi} the expansion of \Z would be empty, because the "frozen relax" token becomes part of the "true branch" and so it disappears.

When is TeX inserting the "frozen relax"?

TeX keeps track of the nesting of conditionals and the insertion of the frozen relax happens when an \else or \fi is encountered at the same level as the conditional it's being evaluated and the process of expansion for this evaluation hasn't yet finished.

So, for instance, TeX adds one in

\ifnum0=1\else\fi

because a <number> is collected by expanding the following tokens. Another case is

\if\fi

which results in an empty expansion because two frozen relax tokens are inserted, which are equal as far as \if is concerned. Also

\if\relax\fi

inserts a frozen relax, but again, \if compares \relax to the frozen relax token and the test returns truth.

2

In simpler language, there are two TeX scanning rules to keep in mind:

1) The expansion of \ifnum...\fi is empty a if the test is false, \relax (frozen) otherwise.

   true condtion -> \relax (frozen)
   false condition -> empty 

2) TeX when reading integers will read until it finds something unexpandable such as a space.

Consider the following MWE:

\tracingall
\count0=5
\count13=5
\count0=2\ifnum\count0=\count1 3 some words\fi9\par%false->empty 
\the\count0 %29
\bye

Here, we see both rules in operation, TeX is trying to put a value into \count0=2, but continues to scan until it finds an unexpandable token. It encounters the conditional. It evaluates the condition (which is false) and as per rule 1) the ifnum..\fi are let to empty. The scanning is then completed and count0=2{empty}9, hence 29.

Modifying the MWE to complete the discussion (\ifnum\count0=\count13).

\tracingall
\count0=5
\count13=5
\count0=2\ifnum\count0=\count13 some words\fi9\par% true>\relax  prints some words 9
\the\count0 % has the value of 2
\bye

If you have a conditional in an \edef, it behaves exactly the same way as edef expands its contents. The second part of your question stems from the fact that the relax inserted by TeX is a "frozen" relax and hard-coded into the engine. (See example at the bottom of https://tex.stackexchange.com/a/57404/963).

a It appears that egreg and David Kastrup call this emptiness and the \relax an unfinished conditional.

3
  • Sorry, but your assertion about the expansion of \ifnum is still incorrect. The "frozen relax" is inserted only in some cases and \edef\x{\ifnum0=0 \else\fi} results in an empty meaning for \x even if the test is true.
    – egreg
    May 26, 2012 at 14:10
  • @egreg empty meaning or space? Can you expand on the only? May 26, 2012 at 14:18
  • The "frozen" relax is inserted only when TeX finds an \else or \fi at the same level as the conditional it's evaluating, while collecting tokens to proceed to the evaluation. In the example I've given the expansion of \x is empty, because the space after the second 0 is ignored by rule.
    – egreg
    May 26, 2012 at 14:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .