I often see code of the following form in package implementations (this example is from the LaTeX3 sources):
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname directlua\endcsname\relax
\else
…
\fi
The first line, containing three \expandafter
s, confuses me. I can only follow this far:
\begingroup
starts a group- The chain of
\expandafter
s causes\csname directlua\endcsname
to be converted to a control sequence - After this point, the state is that we're in a group and
\expandafter\endgroup\ifx[directlua]\relax…
remain to be examined by the macro processor ([directlua]
denotes a control sequence) -
Now the last
\expandafter
is processed and\ifx
is expanded, then\endgroup
ends the group. The TeXbook says this on the topic:When an
\if…
is expanded, TeX reads ahead as far as
necessary to determine whether the condition is true or false; and if
false, it skips ahead (keeping track of\if…\fi
nesting) until
finding the\else
,\or
, or\fi
that ends the skipped text. Similarly,
when\else
,\or
, or\fi
is expanded, TeX reads to the end of any text
that ought to be skipped. The “expansion” of a conditional is empty.This would suggest that the arguments to
\if…
are evaluated inside the group. But what about code inside the conditional's branches?
If the purpose of the code in question is indeed to evaluate the \if…
inside a group, why is it better than just inserting the conditional between \begingroup
and \endgroup
?
Best Answer
Let's look step by step
This becomes
The
\begingroup
has already been digested, so I leave it in parentheses just to remember a group has been opened. Another step, now, where we have to distinguish between cases.Case 1:
\directlua
is not defined, so the token produced by\csname directlua\endcsname
is equivalent to\relax
.Now
\endgroup
is digested and this removes the assignment of the meaning\relax
to\directlua
.A
is examined, the expansion of\else B\fi
is empty.Case 2:
\directlua
is defined.Again
\endgroup
is digested, but does not restore anything. The expansion of\fi
is empty.Why not doing this inside a group? The key point is that at the end
\directlua
is not defined if it wasn't at the start of the process. The same would be true if the code isHowever the purpose of
A
andB
is doing some assignments. In this caseA
would probably be\luatexfalse
, after having said before\newif\ifluatex
, andB
would be\luatextrue
. The triple\expandafter
inside the group dispenses from a global assignment, following the good practice that assignments to a variable should be always global or always local (so long as it's possible). Of course in this case a global assignment would not be that important, in other cases it might have consequences on the save stack.The suggested alternative
(with
\undefined
, not\relax
) is less attractive, because it relies on a certain token to be undefined. One could object that the code we're analyzing assumes\relax
has its primitive meaning, but some assumptions need to be made.If e-TeX can be assumed, the simpler test
is even fully expandable.