Let's look step by step
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname directlua\endcsname\relax
A
\else
B
\fi
This becomes
(\begingroup)\expandafter\endgroup
\ifx\directlua\relax
A
\else
B
\fi
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
.
(\begingroup)\endgroup A\else B\fi
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.
(\begingroup)\endgroup B\fi
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 is
\begingroup\expandafter\ifx\csname directlua\endcsname\relax A\else B\fi\endgroup
However the purpose of A
and B
is doing some assignments. In this case A
would probably be \luatexfalse
, after having said before \newif\ifluatex
, and B
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
{\expandafter}\expandafter\ifx\csname directlua\endcsname\undefined
A
\else
B
\fi
(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
\ifdefined\directlua
A
\else
B
\fi
is even fully expandable.
You can't define a macro \ifdef
that can work with nested conditionals, because of the way TeX keeps track of \else
and \fi
. With a naive definition such as
\def\ifdef#1{\ifx#1\undefined}
one could surely say
\ifdef\CheckMe
\string\CheckMe\space is not defined
\else
\string\CheckMe\space is defined
\fi
but a construction such as
\ifnum\Acount=\Bcount
something else
\else
\ifdef\CheckMe
\string\CheckMe\space is not defined
\fi
\fi
will break if \Acount
is equal to \Bcount
, leaving a stray \fi
: the \else
will be matched to the first \fi
, not to the second, because TeX doesn't expand tokens that are skipped in the true or false branch of a conditional; since \ifdef
is a macro and not a conditional, the mismatch will bite you.
A workaround (tracing back to Knuth himself) is to define a macro in the following way:
\def\isundefined#1{TT\fi\ifx#1\undefined}
and call it as
\if\isundefined\CheckMe
\string\CheckMe\space is not defined
\else
\string\CheckMe\space is defined
\fi
This works also in nested conditionals because TeX will see the \if
and match it with the correct \else
or \fi
. When expanded, \if TT\fi
will do exactly nothing, leaving control to the following \ifx
.
If e-TeX is allowed, there's an \ifdefined
conditional that avoids choosing a macro name and trusting it will remain undefined:
\ifdefined\CheckMe
\string\CheckMe\space is defined
\else
\string\CheckMe\space is not defined
\fi
(notice the reversal of the conditions).
Best Answer
It is an expansion issue. You should expand
\condition
before pass it to\ifthenelse
. Useyou will get correct result.