# What does \begingroup\expandafter…\endgroup do?

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`?

-

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 key point here is to avoid defining `\directlua` at all outside of the test. This approach keeps the hash table clean. –  Joseph Wright Jul 29 '11 at 8:47
@Joseph: You're right, I started thinking of saying it and forgot doing so. –  egreg Jul 29 '11 at 8:49
@Joseph: I think I said something along those lines on comp.text.tex, and got corrected. Control sequences are put in the hash table as soon as they are seen in any kind of token list, and nothing is ever removed from the hash table. The eq table, however, is indeed changed by assignments, and with this contruction is left unchanged. I think that the eTeX manual mentions that \ifdefined and \ifcsname don't add to the hash table. --- all this said, I know very little on that topic. –  Bruno Le Floch Jul 30 '11 at 1:55
@Bruno Yes, with `\csname...\endcsname` the hash table is always touched. The point is just not to have `\directlua` in the equivalence table, which is the most that can be done in pure TeX. –  egreg Jul 30 '11 at 8:12

The reason here is that `\csname ...\endcsname` will define `...` as a macro equal to `\relax` should it not already exists. This feature is used with `\ifx` which compares it to `\relax`. This test is true if `...` wasn't defined before (or was `\let` to `\relax`).

However, it isn't good practice to define macros even to `\relax` just for testing their existence. e-TeX provides `\ifcsname ...\endcsname` for this. Without e-TeX the a group can be used together with `\expandafter` to process both the `\csname` and the `\ifx` inside it to keep the macro definition local.

Note that when an `\if...` is true TeX simply goes on with processing the following tokens. It remembers looking for the closing `\fi` which is simply removed or an `\else` branch which should be skipped. If the test is false everything till `\else` is immediately skipped and TeX again remembers to look for an closing `\fi`. Therefore all the `\expandafter` trickery works very well. The `\ifx` is expanded and TeX already has chosen which branch it will execute. Then the `\endgroup` is insert and that branch is executed.

The benefit for wrapping the whole expression inside a groups is very clear: the actual content can define/change local settings!

Note that that in TeX if-statements and groups are independent (which is not the case in almost any other programming language). You can therefore also write the following to keep the `\csname ...\endcsname` statement local:

``````\begingroup
\expandafter\ifx\csname directlua\endcsname\relax
\endgroup
…
\else
\endgroup
…
\fi
``````

Only one `\endgroup` is ever executed here.

-
There's also `\ifdefined`, so `\ifdefined\directlua` is more direct. –  egreg Jul 29 '11 at 9:05
Missing `\expandafter` ? –  Taco Hoekwater Jul 29 '11 at 11:33
@Martin Scharrer: it is: `\expandafter\ifx\csname directlua\endcsname\relax` (or `\ifx\directlua\undefined`). –  Bruno Le Floch Jul 30 '11 at 1:57
@Bruno: Yes of course. I was locking at the `\begingroup` instead :-) –  Martin Scharrer Jul 30 '11 at 9:36