[Tex/LaTex] Difference between \if and \ifx

conditionalstex-core

I try to understand the subtleties of TeX programming, but it is not always easy.
For example, in the following code :

\def\first{abc}
\def\second{abc}
\ifx\first\second OK!\else false \fi

I understand why the output is OK!.

But I do not understand why the output is false with this code :

\if\first\second OK!\else false \fi

Best Answer

\if compares the following two tokens after macro expansion, because it wants to compare unexpandable tokens.

Thus \if\first\second...\fi expands \first and the input stream has now

\if abc\second...\fi

and the comparison between a and b returns false.

You can make \first and \second unexpandable by saying

\if\noexpand\first\noexpand\second...\fi

but this would return true independently of the meaning of \first and \second, because \if compares character codes and, if a token is not a character, it is considered as having character code 256 (not really, but it is convenient to think so). A control sequence will be considered as having character code 256 unless it has been defined with

\let\cs=a

(or any other character) and in this case \if a\cs would return true.

Of course, the value 256 represents any number that cannot be a character code, so it would be 0x11000 for XeLaTeX or LuaLaTeX, where character codes can be as high as 0x10FFFF.

Usage of \if is not easy, and has many subtleties. For instance one cannot use directly an active character for comparison and it must be preceded (after macro expansion) by \noexpand.

A clever example of \if is for testing whether an argument is empty:

\def\cs#1{%
  \if\relax\detokenize{#1}\relax
    The argument is empty%
  \else
    The argument #1 is non empty%
  \fi
}

It uses \detokenize which is an e-TeX feature. If the argument is empty, the comparison would be between \relax and \relax, which are equal as far as \if is concerned; otherwise, \detokenize would return a string of characters (of category code 12) and \relax is never equal to a character for \if. So with

\cs{abc}

one would get

\if\relax abc\relax
  The argument is empty%
\else
  The argument #1 is non empty%
\fi

and the true text would be

bc\relax The argument is empty\else

which would be discarded.

Similarly, with

\if a\first true\else false\fi

the expansion of \first gives

\if aabctrue\else false\fi

and, since the first two unexpandable tokens after \if are equal, the true text is

bctrue

while \else false\fi will be discarded.

Related Question