30

I am trying to better understand brace hacks. The issue was brought to my attention in egreg's answer, Conflict between eqnarray and tabstackengine, that tabstackengine's failure to protect inner alignment groups could be fixed using brace hacks. David Carlisle pointed me to the TeXbook, and I find them described on p.385.

Now the one used by egreg was similar to but different from the ones on p.385. Below I summarize the 4 given by Knuth, and add 2 more based on egreg's answer, with regards to how they affect the master and balance counter, when expanded and prior to expansion:

TeX Brace Hacks (p.385, TeXbook)
               master  balance
               ex nox  ex nox 
{               1  1    1  1
\bgroup         0  0    0  0 
\iffalse{\fi    1  1    0  1
\ifnum0=`{\fi   0  1    0  1

{\iffalse}\fi   0  0    1  0
{\ifnum0=`}\fi  1  0    1  0

I realize that in addition to alignment groups, brace types influence how math binary/unary categories communicate to adjacent atoms, they can limit the scope of defined data, and some can or cannot be used in macro/environment definitions without the corresponding [balanced] brace.

To this end, I set up an MWE to test the 6 brace types shown above, as well as \begingroup...\endgroup, to see how they behaved and scored each of the results:

% BRACE HACK TESTING/LEARNING
%
\documentclass{article}
\usepackage{amsmath}
\usepackage[margin=3cm]{geometry}
\newenvironment{QQQ}{}{}
\def\blech#1{\blechaux#1\relax}
\def\blechaux#1&#2\relax{#1/#2}
\begin{document}
GRADING ELEMENTS:\\
0/1 does not/does protect inner alignment group\\
0/1 does not/does communicate binary nature across boundary\\
0/1 does not/does preserve defined data across boundary\\
0/1 does not/does work within begining/end of environment definition

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{...}|\hfill Grade 1000

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ {\blech{A&OK}}
\end{aligned}$\hfill
$A{=}B$\hfill${\def\Q{XYZ}}\meaning\Q$

%\renewenvironment{QQQ}{{\catcode`&=12 }{}}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\bgroup...\egroup|\hfill Grade 0001

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ \textrm{BAD ALIGNMENT}%\bgroup\blech{A&OK}\egroup
\end{aligned}$\hfill
$A\bgroup=\egroup B$\hfill$\bgroup\def\Q{XYZ}\egroup\meaning\Q$

\renewenvironment{QQQ}{\bgroup\catcode`&=12 }{\egroup}
\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\iffalse{\fi...\iffalse}\fi|\hfill Grade 1110

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \iffalse{\fi\blech{A&OK}\iffalse}\fi
\end{aligned}$\hfill
$A\iffalse{\fi=\iffalse}\fi B$\hfill$\iffalse{\fi\def\Q{XYZ}\iffalse}\fi\meaning\Q$

%\renewenvironment{QQQ}{\iffalse{\fi\catcode`&=12 }{\iffalse}\fi}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\ifnum0=`{\fi...\ifnum0=`}\fi|\hfill Grade 0110

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \textrm{BAD ALIGNMENT}%\ifnum0=`{\fi\blech{A&OK}\ifnum0=`}\fi
\end{aligned}$\hfill
$A\ifnum0=`{\fi=\ifnum0=`}\fi B$\hfill$\ifnum0=`{\fi\def\Q{XYZ}\ifnum0=`}\fi\meaning\Q$

%\renewenvironment{QQQ}{\ifnum0=`{\fi\catcode`&=12 }{\ifnum0=`}\fi}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{\iffalse}\fi...\iffalse{\fi}|\hfill Grade 0001

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \textrm{BAD ALIGNMENT}% {\iffalse}\fi\blech{A&OK}\iffalse{\fi}
\end{aligned}$\hfill
$A{\iffalse}\fi=\iffalse{\fi} B$\hfill${\iffalse}\fi\def\Q{XYZ}\iffalse{\fi}\meaning\Q$

\renewenvironment{QQQ}{{\iffalse}\fi\catcode`&=12 }{\iffalse{\fi}}
\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{\ifnum0=`}\fi...\ifnum0=`{\fi}|\hfill Grade 1001

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ {\ifnum0=`}\fi\blech{A&OK}\ifnum0=`{\fi}
\end{aligned}$\hfill
$A{\ifnum0=`}\fi=\ifnum0=`{\fi}B$\hfill${\ifnum0=`}\fi\def\Q{XYZ}\ifnum0=`{\fi}\meaning\Q$

\renewenvironment{QQQ}{{\ifnum0=`}\fi\catcode`&=12 }{\ifnum0=`{\fi}}
\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\begingroup...\endgroup|\hfill Grade 0101

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ \textrm{BAD ALIGNMENT}%\begingroup\blech{A&OK}\endgroup}\meaning \Q
\end{aligned}$\hfill
$A\begingroup=\endgroup B$\hfill$\begingroup\def\Q{XYZ}\endgroup\meaning\Q$

\renewenvironment{QQQ}{\begingroup\catcode`&=12 }{\endgroup}
\begin{QQQ}&&&\end{QQQ}

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}

enter image description here

The grade is a 4-digit number, each successive digit describing a "do or not do" to 4 questions:

  1. gets a 1 if the brace method protects inner alignment groups (A/OK vs. BAD ALIGNMENT)

  2. gets a 1 if surrounding math atoms can communicate their presence through the boundary (A = B vs. A=B)

  3. gets a 1 if an inner macro definition is preserved outside of the grouping (macro:-> XYZ vs. undefined)

  4. gets a 1 if the unbalanced version of the brace type can be used in an environment (&&& vs. BAD ENV. DEFINITION).

For completeness, I guess I should note that the absence of any bracing (not performed in my MWE) would get a score of 0111.

This was all very enlightening to me, but I had originally been thinking that there must be more differences (tests to perform) that can differentiate these methods that I am missing. However, that thinking was based on a typo in my code that Marcel caught and pointed out. Nonetheless, there may be more tests to further differentiate the results. Also, my results (the "grade") describes things differently than Knuth, who instead describes the differences in terms of effects on master and balance counters, for both expanded and unexpanded states of input.

I also note that my limited set of tests would indicate that \bgroup...\egroup behaves in the exact same manner as {\iffalse}\fi...\iffalse{\fi}. Is this actually the case?

So the question is simply, are there other tests can be run to further differentiate the behavior of the seven different bracing techniques shown in my MWE? Are there additional brace hacks that bring further nuance to the question?

p.s. I have submitted a revision of tabstackengine to ctan.org today, which fixes the inner alignment group issue and provides some new features.


RESULTS, THANKS TO MARCEL'S ANSWER AND GuM's SUGGESTION

Thanks to Marcel's answer, two important things were learned:

  1. I had a typo in my original question that was causing one of my misunderstandings (without taking anything away from Marcel's answer, I edited the original question to fix it since typos generally make for really bad questions)

  2. A 5th test was added to the mix, to further differentiate the grade: whether the brace hack could be used to delimit an \edef.

In addition, GuM suggested two possible brace hacks, one of which proved uniquely successful: \iffalse{\fi\ifnum0=‘}\fi...\ifnum0=‘{\fi\iffalse}\fi. I have added it to my list.

I show those updated results below, and include the control case of "no delimiters whatsoever". With this 5th test, the results are fully clarified, showing that no two brace hacks perform identically for the 5 tests, and it further emerges that some are complementary (opposite) bracing conditions:

  1. The case of no delimiters and brace {...} delimiters were complementary, with grades of 01110 and 10001, respectively.

  2. the case of \iffalse{\fi...\iffalse}\fi and {\iffalse}\fi...\iffalse{\fi} were complementary, with grades of 11100 and 00011, respectively.

  3. The case of \ifnum0=‘{\fi...\ifnum0=‘}\fi and {\ifnum0=‘}\fi...\ifnum0=‘{\fi} were complementary, with grades of 01100 and 10011, respectively.

  4. The remaining two cases, \bgroup...\egroup and \begingroup...\endgroup were similar, except for the well known distinction that the latter will allow math classes to see across the boundary to adjacent math atoms. Their respective scores were 00010 and 01010.

  5. Gum's suggested brace hack has the most comprehensive score of 11110, which means it protects/isolates inner alignment groups, provides knowledge of math atoms across boundaries, preserves inner defined data across the outer boundary, and works as an open/close pair in begin/end environment definitions. It only fails in that it cannot delimit an \edef.

Perhaps Marcel's coolest discernment in his answer was that the {\iffalse}\fi...\iffalse{\fi} brace hack could be used across an environment definition in order to capture the fully expanded contents of the environment; A very unique insight.

The updated MWE, incorporating all that I've learned here:

% BRACE HACK TESTING/LEARNING
%
\documentclass{article}
\usepackage{amsmath}
\usepackage[margin=3cm,top=2cm,bottom=2cm]{geometry}
\newenvironment{QQQ}{}{}
\def\blech#1{\blechaux#1\relax}
\def\blechaux#1&#2\relax{#1/#2}
\begin{document}
GRADING ELEMENTS:\\
0/1 does not/does protect/isolate inner alignment groups.\\
0/1 does not/does provide knowledge of math atoms across boundary.\\
0/1 does not/does preserve inner-defined data across outer boundary.\\
0/1 does not/does work as open/close pair in the begining/end of environment definition.\\
0/1 does not/does work as delimiters to an \textbackslash edef.

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|...| (absence of delimiters)\hfill Grade 01110

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{...}|\hfill Grade 10001

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ {\blech{A&OK}}
\end{aligned}$\hfill
$A{=}B$\hfill${\def\Q{XYZ}}\meaning\Q$

%\renewenvironment{QQQ}{{\catcode`&=12 }{}}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}
\hfill\edef\QQ{\today}[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\bgroup...\egroup|\hfill Grade 00010

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ \textrm{BAD ALIGNMENT}%\bgroup\blech{A&OK}\egroup
\end{aligned}$\hfill
$A\bgroup=\egroup B$\hfill$\bgroup\def\Q{XYZ}\egroup\meaning\Q$

\renewenvironment{QQQ}{\bgroup\catcode`&=12 }{\egroup}
\begin{QQQ}&&&\end{QQQ}
\hfill CAN'T EDEF%\edef\QQ\bgroup\today\egroup[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\iffalse{\fi...\iffalse}\fi|\hfill Grade 11100

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \iffalse{\fi\blech{A&OK}\iffalse}\fi
\end{aligned}$\hfill
$A\iffalse{\fi=\iffalse}\fi B$\hfill$\iffalse{\fi\def\Q{XYZ}\iffalse}\fi\meaning\Q$

%\renewenvironment{QQQ}{\iffalse{\fi\catcode`&=12 }{\iffalse}\fi}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}
\hfill CAN'T EDEF%\edef\QQ\iffalse{\fi\today\iffalse}\fi[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\ifnum0=`{\fi...\ifnum0=`}\fi|\hfill Grade 01100

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \textrm{BAD ALIGNMENT}%\ifnum0=`{\fi\blech{A&OK}\ifnum0=`}\fi
\end{aligned}$\hfill
$A\ifnum0=`{\fi=\ifnum0=`}\fi B$\hfill$\ifnum0=`{\fi\def\Q{XYZ}\ifnum0=`}\fi\meaning\Q$

%\renewenvironment{QQQ}{\ifnum0=`{\fi\catcode`&=12 }{\ifnum0=`}\fi}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}
\hfill CAN'T EDEF%\edef\QQ\ifnum0=`{\fi\today\ifnum0=`}\fi[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{\iffalse}\fi...\iffalse{\fi}|\hfill Grade 00011

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \textrm{BAD ALIGNMENT}% {\iffalse}\fi\blech{A&OK}\iffalse{\fi}
\end{aligned}$\hfill
$A{\iffalse}\fi=\iffalse{\fi} B$\hfill${\iffalse}\fi\def\Q{XYZ}\iffalse{\fi}\meaning\Q$

\renewenvironment{QQQ}{{\iffalse}\fi\catcode`&=12 }{\iffalse{\fi}}
\begin{QQQ}&&&\end{QQQ}
\hfill\edef\QQ{\iffalse}\fi\today\iffalse{\fi}[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{\ifnum0=`}\fi...\ifnum0=`{\fi}|\hfill Grade 10011

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ {\ifnum0=`}\fi\blech{A&OK}\ifnum0=`{\fi}
\end{aligned}$\hfill
$A{\ifnum0=`}\fi=\ifnum0=`{\fi}B$\hfill${\ifnum0=`}\fi\def\Q{XYZ}\ifnum0=`{\fi}\meaning\Q$

\renewenvironment{QQQ}{{\ifnum0=`}\fi\catcode`&=12 }{\ifnum0=`{\fi}}
\begin{QQQ}&&&\end{QQQ}
\hfill\edef\QQ{\ifnum0=`}\fi\today\ifnum0=`{\fi}[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\begingroup...\endgroup|\hfill Grade 01010

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ \textrm{BAD ALIGNMENT}%\begingroup\blech{A&OK}\endgroup}
\end{aligned}$\hfill
$A\begingroup=\endgroup B$\hfill$\begingroup\def\Q{XYZ}\endgroup\meaning\Q$

\renewenvironment{QQQ}{\begingroup\catcode`&=12 }{\endgroup}
\begin{QQQ}&&&\end{QQQ}
\hfill CAN'T EDEF%\edef\QQ\begingroup\today\endgroup[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\iffalse{\fi\ifnum0=`}\fi...\ifnum0=`{\fi\iffalse}\fi|\hfill 
  Grade 11110

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ \iffalse{\fi\ifnum0=`}\fi\blech{A&OK}\ifnum0=`{\fi\iffalse}\fi
\end{aligned}$\hfill
$A\iffalse{\fi\ifnum0=`}\fi=\ifnum0=`{\fi\iffalse}\fi B$
\hfill$\iffalse{\fi\ifnum0=`}\fi\def\Q{XYZ}\ifnum0=`{\fi\iffalse}\fi\meaning\Q$

\renewenvironment{QQQ}{\iffalse{\fi\ifnum0=`}\fi\catcode`&=12 }{\ifnum0=`{\fi\iffalse}\fi}
\begin{QQQ}&&&\end{QQQ}
\hfill CAN'T EDEF%\edef\QQ\iffalse{\fi\ifnum0=`}\fi\today\ifnum0=`{\fi\iffalse}\fi[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\clearpage

{\LARGE\bfseries FAILED CASES}

The following case has a score of \verb|01110|, which is identical
  to the case of ``absent delimiters.''
Thus, it is currently excluded as a ``brace hack'' as it provides no added value.

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|\ifnum0=`{\fi\iffalse}\fi...\iffalse{\fi\ifnum0=`}\fi|\hfill 
Grade 01110

$\begin{aligned}
y&=mx + b\\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ \textrm{BAD ALIGNMENT}%\ifnum0=`{\fi\iffalse}\fi\blech{A&OK}\iffalse{\fi\ifnum0=`}\fi
\end{aligned}$\hfill
$A\ifnum0=`{\fi\iffalse}\fi=\iffalse{\fi\ifnum0=`}\fi B$
\hfill$\ifnum0=`{\fi\iffalse}\fi\def\Q{XYZ}\iffalse{\fi\ifnum0=`}\fi\meaning\Q$

\renewenvironment{QQQ}{\ifnum0=`{\fi\iffalse}\fi\catcode`&=12 }{\iffalse{\fi\ifnum0=`}\fi}
\begin{QQQ}&&&\end{QQQ}
\hfill CAN'T EDEF%\edef\QQ\ifnum0=`{\fi\iffalse}\fi\today\iffalse{\fi\ifnum0=`}\fi[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

These two cases below produce the same grades as the same as the simpler 
  \verb|\iffalse| and \verb|\ifnum| cases.
Thus, they provide no added value to the list of ``brace hacks.''

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{\iffalse{\fi}...{\iffalse}\fi}|\hfill Grade 11100

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ {\iffalse{\fi}\blech{A&OK}{\iffalse}\fi}
\end{aligned}$\hfill
$A{\iffalse{\fi}={\iffalse}\fi}B$%
\hfill${\iffalse{\fi}\def\Q{XYZ}{\iffalse}\fi}\meaning\Q$

%\renewenvironment{QQQ}{{\iffalse{\fi}\catcode`&=12 }{{\iffalse}\fi}}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}
\hfill\edef\QQ{\iffalse{\fi}executed, not \verb|\edef|ed{\iffalse}\fi}[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$\bullet$Case \verb|{\ifnum0=`{\fi}...{\ifnum0=`}\fi}|\hfill Grade 01100

$\begin{aligned}
y&=mx + b\\
E&=mc^2
+ BAD ALIGNMENT%{\ifnum0=`{\fi}\blech{A&OK}{\ifnum0=`}\fi}
\end{aligned}$\hfill
$A{\ifnum0=`{\fi}={\ifnum0=`}\fi}B$%
\hfill${\ifnum0=`{\fi}\def\Q{XYZ}{\ifnum0=`}\fi}\meaning\Q$

%\renewenvironment{QQQ}{{\ifnum0=`{\fi}\catcode`&=12 }{{\ifnum0=`}\fi}}
BAD ENV. DEFINITION%\begin{QQQ}&&&\end{QQQ}
\hfill\edef\QQ{\ifnum0=`{\fi}executed, not \verb|\edef|ed{\ifnum0=`}\fi}[\QQ]

\noindent\hrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}

enter image description here

enter image description here

The updated counter-change table is

TeX Brace Hacks (p.385, TeXbook)
                          master  balance
                          ex nox  ex nox 
{                          1  1    1  1  (Knuth)
\bgroup                    0  0    0  0  (Knuth)
\iffalse{\fi               1  1    0  1  (Knuth)
\ifnum0=`{\fi              0  1    0  1  (Knuth)

{\iffalse}\fi              0  0    1  0  (egreg inspired)
{\ifnum0=`}\fi             1  0    1  0  (egreg used)
\iffalse{\fi\ifnum0=`}\fi  1  0    0  0  (GuM suggestion)

Some correlations between my 5-digit grades and this counter table can be established:

  1. In order to get a grade of 1 in the 1st digit (the ability to protect/isolate inner alignment groups), the expanded master counter must increase by 1.

  2. In order to get a grade of 1 in the 4th digit (be able to use as open/close pair in the begin/end of an environment), the unexpanded balance (or master) counter must not increase (has a value of 0).

  3. In order to provide delimiters for an \edef, the expanded balance counter must increase by 1.

Unrelated to the counter table, but observed from the graded results (excluding \begingroup...\endgroup which is in a category by itself), grades of 1 in digits 2 and 3 (knowledge of math atoms across boundary and preservation of inner-defined data) can only occur if there are no unconditional occurrences of {...} or \bgroup...\egroup.

Thanks for putting up with this extended question!

  • 5
    Thanks for this question; this will be a prime exhibit in showing why TeX macros are such a perverse “language” to write code in. :-) – ShreevatsaR Mar 6 '18 at 4:30
  • 2
    I don’t understand exactly where you want to get with this, but perhaps you should also take an interest in \iffalse{\fi\ifnum`}=\z@\fi and \ifnum`{=\z@\fi\iffalse}\fi. – GuM Mar 6 '18 at 8:42
  • @GuM I also investigated {\iffalse{\fi}...{\iffalse}\fi} and {\ifnum0=‘{\fi}...{\ifnum0=‘}\fi}. These cases turned out identical to the simpler \iffalse{\fi...\iffalse}\fi and \ifnum0=‘{\fi...\ifnum0=‘}\fi cases, respectively. – Steven B. Segletes Mar 6 '18 at 15:24
  • @StevenB.Segletes You might want to retest the pair suggested by GuM. It normally should score 11110. – Marcel Krüger Mar 6 '18 at 16:00
  • 1
    @GuM As Marcel notes, the case of \iffalse{\fi\ifnum0=‘}\fi...\ifnum0=‘{\fi\iffalse}\fi actually produces a score of 11110 (awesome!!), whereas the case of \ifnum0=‘{\fi\iffalse}\fi...\iffalse{\fi\ifnum0=‘}\fi seems get a score of 01110, which is the same as the "absent delimiters" case. – Steven B. Segletes Mar 6 '18 at 16:29
19

The fourth case is actually 0110, the 1110 came from a typo in the code: Your test

E&=mc^2
+ {\ifnum0=`}\fi\blech{A&OK}\ifnum0=`{\fi}

is the test for the sixth case, it should be

E&=mc^2
+ \ifnum0=`{\fi\blech{A&OK}\ifnum0=`}\fi

instead.

This leaves {\iffalse}\fi...\iffalse{\fi} and \bgroup...\egroup. According to the TeXbook, the difference lies in the expanded version of the balance counter. The balance counter is used for example for macro definitions and we need expansion, so we can construct an additional test:

  1. Can be used to delimit the definition of an \edef.

This will fail for \bgroup...\egroup, because in

\edef\something\bgroup ABC\egroup

\bgroup ABC\egroup is interpreted as the parameter text, while there is no problem with

\edef\something{\iffalse}\fi ABC\iffalse{\fi}

Actually the combination of this with environments allows for a quite interesting hack: You can capture the fully expanded content of an environment in a macro:

\newenvironment{EDEF}[1]{\xdef#1{\iffalse}\fi}{\iffalse{\fi}}
\begin{EDEF}\ABCD
  Something interesting
\end{EDEF}

This defines a macro \ABCD as the full expansion of Something interesting.

  • Thank you for pointing out the typo! I will edit my question to reflect that. – Steven B. Segletes Mar 6 '18 at 11:29
  • 1
    Your answer is really quite thorough. You caught the typo, which resolved the one conundrum, and you developed a test to differentiate what I could not differentiate. Thank you so much for this really nice answer. – Steven B. Segletes Mar 6 '18 at 11:50
  • 6
    +1 for the EDEF environment. Impressive! – Phelype Oleinik Mar 6 '18 at 12:24
10

Perhaps I should add some explanation about the \iffalse{\fi\ifnum`}=\z@\fi ... ifnum`{=\z@\fi\iffalse}\fi hack (note that the intended usage is with the “delimiters” in this order: I never meant to suggest using them in flipped order, that is, ifnum`{=\z@\fi\iffalse}\fi ... \iffalse{\fi\ifnum`}=\z@\fi).

Before writing my comment, I had been trying to figure out what the OP was attempting to achieve in connection with @egreg’s answer. I was too lazy to look into the code of the tabstackengine package, nonetheless I got the vague intuition that he was looking for a brace hack to be used to “wrap up” the definition of a command, or of an environment, in such a way that:

  • occurences of & (or \cr) tokens inside the argument of the command, or the contents of the environment, are “shielded” from being interpreted as belonging to an outer alignment, if the command or the environment happen to be used in the context of an outer alignment;

  • on the other hand, the braces should not be “executed” in the stomach, which means that no subgroup, or subformula, will be created, thus allowing proper interpretation of math atoms and preventing definitions issued inside the command or the environment from being regarded as local.

Given these requirements, the hack almost suggested itself. Indeed, consider, for example, the following alternative to @egreg’s suggested patch to the code of tabstackengine:

\makeatletter
\renewcommand\ensureTABstackMath[1]{%
  \iffalse{\fi\ifnum`}=\z@\fi
  \let\sv@TABmode\TAB@delim\TABstackMath#1\let\TAB@delim\sv@TABmode
  \ifnum`{=\z@\fi\iffalse}\fi
}
\makeatother

Recall that TeX does expand tokens when it is reading alignment entries (contrast this with the case of the alignment preamble). Now, \iffalse{\fi increments the master counter, even if the brace itself is discarded and is not contributed to the current token list, as documented on p. 385 of The TeXbook; on the other hand, the following \ifnum`}=\z@\fi (which, in general, we need in order to build a definition with properly balanced braces—note that it is not needed in this particular case, we could simply say

\makeatletter
\renewcommand\ensureTABstackMath[1]{%
  \iffalse{\fi
  \let\sv@TABmode\TAB@delim\TABstackMath#1\let\TAB@delim\sv@TABmode
  \iffalse}\fi
}
\makeatother

and it would work fine; note also that, since TeX does not expand tokens in the replacement text, it doesn’t even realize that the } in \ifnum`}=\z@\fi is part of a numeric costant), the following \ifnum`}=\z@\fi, we were saying, leaves the master counter unchanged; so, the net change is +1. Things go similarly for the ifnum`{=\z@\fi\iffalse}\fi case, with a net change in the master counter of -1, yet with no brace being actually contributed to the current token list.

Since it has the desired effect on the master counter, the construction is effective in “shielding” inner & tokens from an outer alignment; since no brace actually reaches TeX’s stomach, the construction doesn’t produce a subformula that would interfere with the concatenation of atoms in the current math list, or a subgroup that would keep definitions local.

Finally, it is obvious that the idiom cannot be used to delimit an expanded definition (\edef/\xdef), since it is meant exactly to behave as “a pair of braces that exist only for the purpose of nesting alignments, and for no other one”.


Addition

It should be noted that the \iffalse{\fi\ifnum`}=\z@\fi ... \ifnum`{=\z@\fi\iffalse}\fi pair is, in essence, exactly the pair of “brace-like” idioms that the mhsetup package (invoked by mathtools) defines as the \MH_group_align_safe_begin:/\MH_group_align_safe_end: pair. Indeed, the definition we find in mhsetup.sty is

\def \MH_group_align_safe_begin: {\iffalse{\fi\ifnum0=`}\fi}
\def \MH_group_align_safe_end:   {\ifnum0=`{}\fi}

which gives the same result, but using fewer tokens in the definition of the closing “brace”. Let us discuss briefly how it works.

  1. When the macros are being defined, the tokens in the replacement text are not “executed”, they are just stored away keeping count of {/} nested pair; since the replacement text of both macros contains balanced {/} pairs, both definitions are correctly carried out.

  2. When TeX is scanning the entry of an alignment, on the other hand, tokens are expanded, which means in particular that conditionals are evaluated. Now:

    a) for the purpose of deciding when the entry terminates, for which only the master counter matters, the evaluation of the numeric constants inside the conditionals \ifnum0=`}\fi and \ifnum0=`{}\fi (constants that are evaluated exactly because the conditionals are) have the effect documented on p. 385 of The TeXbook; thus \MH_group_align_safe_begin: increments the master counter, while \MH_group_align_safe_end: decrements it, as desired;

    b) for the purpose of deciding which tokens are forwarded to TeX’s stomach, note that, in the above definitions, all braces are discarded because they occur in the false branch of a conditional: this is true also of the } inside the \ifnum0=`{}\fi test, because the ASCII code of { is not zero!

    In particular, b) shows that there is no need to add a second conditional (namely, \iffalse ... \fi) around the } token in the definition of \MH_group_align_safe_end:. Unfortunately, a similar trick doesn’t work for \MH_group_align_safe_begin: (just think of it).

I hope to be able to further improve this answer during Easter vacation (if nobody else has done so by then!).

  • 1
    Thank you for taking the time to add your expertise to the mix. – Steven B. Segletes Mar 7 '18 at 0:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.