I'd attack this from a different point of view. Primitive conditionals in TeX test for a condition, which can absorb tokens from the input stream or not until the truth or falsehood of the condition can be established. So, let's denote by
<IF>
the primitive conditional together with the (possibly empty) list of tokens that must be absorbed. For instance \ifhmode
needs no token, \ifx
needs two. In some cases (\if
, \ifcat
, \ifnum
, \ifdim
) TeX perform expansions in order to find the required kind of tokens for the test; in others (\ifx
, \ifmmode
, \ifhmode
, \ifvmode
\ifinner
, \iftrue
, \iffalse
) no expansion is performed. Thus <IF>
will denote the conditional and the required tokens after expansion has taken place and the condition can be tested.
The typical construction you're referring to is
<IF>
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
where we already have
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
More generally, we have
<IF><true>\else<false>\fi
or
\IF<true>\fi
where both <true>
and <false>
can be empty.
The condition is true
TeX will simply remove <IF>
from the input stream, leaving either
<true>\else<false>\fi
or
<true>\fi
The condition is false
TeX looks for the next \else
token, taking into account nested conditionals that might appear in <true>
without expanding anything. So an \else
belonging to a nested \if...\else\fi
inside <true>
will be skipped. The expansion is empty also in this case and every token up to \else
will disappear. In case no matching \else
is found, TeX will stop looking at the matching \fi
that should better be somewhere. So, in the two cases, we'd get either
<false>\fi
or just nothing if no \else
branch was there.
This is proved by the following TeX input:
\def\showx{\show\x}
\def\showif{\afterassignment\showx
\expandafter\def\expandafter\x\expandafter}
\showif{\ifvmode<true>\else<false>\fi}
\showif{\ifvmode<true>\fi}
\showif{\ifhmode<true>\else<false>\fi}
\showif{\ifhmode<true>\fi}
\bye
Running TeX on it will produce the following transcript:
This is TeX, Version 3.1415926 (TeX Live 2012)
(./plkfi.tex
> \x=macro:
-><true>\else <false>\fi .
\showx ->\show \x
l.5 \showif{\ifvmode<true>\else<false>\fi}
?
> \x=macro:
-><true>\fi .
\showx ->\show \x
l.6 \showif{\ifvmode<true>\fi}
?
> \x=macro:
-><false>\fi .
\showx ->\show \x
l.7 \showif{\ifhmode<true>\else<false>\fi}
?
> \x=macro:
->.
\showx ->\show \x
l.8 \showif{\ifhmode<true>\fi}
?
What happens next
The expansion of \else
consists in removing everything up to the matching \fi
and leaving nothing in the input stream. Nested conditionals will be taken into account as before.
The expansion of \fi
is empty.
The role of \expandafter
Now we have the bases upon which we can drop \expandafter
.
Let's see a typical usage:
\def\@ifundefined#1{%
\expandafter\ifx\csname#1\endcsname\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
What we want is to be able to say
\@ifundefined{foo}{T}{F}
So the macro built with the argument as name is compared to \relax
(this is really the uninteresting part) and then the true or false branch is followed.
After the removal of the <IF>
we remain with
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi{T}{F}
and now TeX duly expands the first token. This triggers the expansion of \else
and here's where the fun begins.
The expansion of \expandafter
consists in expanding (if possible) the token after the next one and vanishing. Thus \else
is expanded according to the rule above and we are left with
\@firstoftwo{T}{F}
that results in leaving T
in the input stream.
Suppose now that the condition is false. Then the <IF>
is removed together with everything up to \else
, leaving
\expandafter\@secondoftwo\fi{T}{F}
Now \expandafter
does its job of expanding \fi
and vanishing. Thus we get
\@secondoftwo{T}{F}
that finally leaves F
.
Important note
In the case of \@ifundefined{foo}{T}{F}
we are able to get at T
or F
without ever executing a command: just macro expansion has been used. This makes \@ifundefined
and similarly defined macro usable inside \edef
:
\edef\test{\@ifundefined{foo}{T}{F}}
will be equivalent to
\def\test{T}
in case \foo
is defined (and not equivalent to \relax
, as usual in LaTeX) or to
\def\test{F}
if \foo
is undefined (or equivalent to \relax
).
What would happen without \expandafter
? With a true conditional TeX would be confronted with
\@firstoftwo\else\@secondoftwo\fi{T}{F}
and the two arguments to \@firstoftwo
would be \else
and \@secondoftwo
, which wouldn't do anything useful, would they?
Similarly, for a false condition we'd get
\@secondoftwo\fi{T}{F}
and again things would go wrong.
\expandafter
s are important but nobody says why ...\let\next=...
idiom). Alan Jeffrey popularised it and introduced it to the LaTeX sources for latex2e, although I seem to recall he denied inventing it and had picked it up from somewhere....\if..
and not\@firstof..
compare latex2.09\def\@iwhiledim#1{\ifdim #1\let\@nextwhile\@iwhiledim\else\let\@nextwhile\@whilenoop\fi\@nextwhile{#1}}
with latex2e\long\def\@iwhiledim#1{\ifdim #1\expandafter\@iwhiledim\else\expandafter\@gobble\fi{#1}}