Understanding Brace Hacks
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 1000
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 1110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 0110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 0001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}meaning Q
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
The grade is a 4-digit number, each successive digit describing a "do or not do" to 4 questions:
gets a 1 if the brace method protects inner alignment groups (
A/OK
vs.BAD ALIGNMENT
)gets a 1 if surrounding math atoms can communicate their presence through the boundary (
A = B
vs.A=B
)gets a 1 if an inner macro definition is preserved outside of the grouping (
macro:-> XYZ
vs.undefined
)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:
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)
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{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}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:
The case of no delimiters and brace
{...}
delimiters were complementary, with grades of01110
and10001
, respectively.the case of
iffalse{fi...iffalse}fi
and{iffalse}fi...iffalse{fi}
were complementary, with grades of11100
and00011
, respectively.The case of
ifnum0=‘{fi...ifnum0=‘}fi
and{ifnum0=‘}fi...ifnum0=‘{fi}
were complementary, with grades of01100
and10011
, respectively.The remaining two cases,
bgroup...egroup
andbegingroup...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 were00010
and01010
.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 anedef
.
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|...| (absence of delimiters)hfill Grade 01110
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 10001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{today}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbgrouptodayegroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 11100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fitodayiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 01100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fitodayifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 00011
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse}fitodayiffalse{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`}fitodayifnum0=`{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbegingrouptodayendgroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fiifnum0=`}fi...ifnum0=`{fiiffalse}fi|hfill
Grade 11110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiifnum0=`}fiblech{A&OK}ifnum0=`{fiiffalse}fi
end{aligned}$hfill
$Aiffalse{fiifnum0=`}fi=ifnum0=`{fiiffalse}fi B$
hfill$iffalse{fiifnum0=`}fidefQ{XYZ}ifnum0=`{fiiffalse}fimeaningQ$
renewenvironment{QQQ}{iffalse{fiifnum0=`}ficatcode`&=12 }{ifnum0=`{fiiffalse}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fiifnum0=`}fitodayifnum0=`{fiiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clearpage
{LARGEbfseries 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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fiiffalse}fi...iffalse{fiifnum0=`}fi|hfill
Grade 01110
$begin{aligned}
y&=mx + b\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiiffalse}fiblech{A&OK}iffalse{fiifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fiiffalse}fi=iffalse{fiifnum0=`}fi B$
hfill$ifnum0=`{fiiffalse}fidefQ{XYZ}iffalse{fiifnum0=`}fimeaningQ$
renewenvironment{QQQ}{ifnum0=`{fiiffalse}ficatcode`&=12 }{iffalse{fiifnum0=`}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fiiffalse}fitodayiffalse{fiifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.''
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{iffalse}fi}meaningQ$
%renewenvironment{QQQ}{{iffalse{fi}catcode`&=12 }{{iffalse}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse{fi}executed, not verb|edef|ed{iffalse}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{ifnum0=`}fi}meaningQ$
%renewenvironment{QQQ}{{ifnum0=`{fi}catcode`&=12 }{{ifnum0=`}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`{fi}executed, not verb|edef|ed{ifnum0=`}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
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{fiifnum0=`}fi 1 0 0 0 (GuM suggestion)
Some correlations between my 5-digit grades and this counter table can be established:
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.
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).
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!
tex-core braces
|
show 2 more comments
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 1000
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 1110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 0110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 0001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}meaning Q
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
The grade is a 4-digit number, each successive digit describing a "do or not do" to 4 questions:
gets a 1 if the brace method protects inner alignment groups (
A/OK
vs.BAD ALIGNMENT
)gets a 1 if surrounding math atoms can communicate their presence through the boundary (
A = B
vs.A=B
)gets a 1 if an inner macro definition is preserved outside of the grouping (
macro:-> XYZ
vs.undefined
)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:
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)
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{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}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:
The case of no delimiters and brace
{...}
delimiters were complementary, with grades of01110
and10001
, respectively.the case of
iffalse{fi...iffalse}fi
and{iffalse}fi...iffalse{fi}
were complementary, with grades of11100
and00011
, respectively.The case of
ifnum0=‘{fi...ifnum0=‘}fi
and{ifnum0=‘}fi...ifnum0=‘{fi}
were complementary, with grades of01100
and10011
, respectively.The remaining two cases,
bgroup...egroup
andbegingroup...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 were00010
and01010
.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 anedef
.
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|...| (absence of delimiters)hfill Grade 01110
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 10001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{today}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbgrouptodayegroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 11100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fitodayiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 01100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fitodayifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 00011
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse}fitodayiffalse{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`}fitodayifnum0=`{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbegingrouptodayendgroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fiifnum0=`}fi...ifnum0=`{fiiffalse}fi|hfill
Grade 11110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiifnum0=`}fiblech{A&OK}ifnum0=`{fiiffalse}fi
end{aligned}$hfill
$Aiffalse{fiifnum0=`}fi=ifnum0=`{fiiffalse}fi B$
hfill$iffalse{fiifnum0=`}fidefQ{XYZ}ifnum0=`{fiiffalse}fimeaningQ$
renewenvironment{QQQ}{iffalse{fiifnum0=`}ficatcode`&=12 }{ifnum0=`{fiiffalse}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fiifnum0=`}fitodayifnum0=`{fiiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clearpage
{LARGEbfseries 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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fiiffalse}fi...iffalse{fiifnum0=`}fi|hfill
Grade 01110
$begin{aligned}
y&=mx + b\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiiffalse}fiblech{A&OK}iffalse{fiifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fiiffalse}fi=iffalse{fiifnum0=`}fi B$
hfill$ifnum0=`{fiiffalse}fidefQ{XYZ}iffalse{fiifnum0=`}fimeaningQ$
renewenvironment{QQQ}{ifnum0=`{fiiffalse}ficatcode`&=12 }{iffalse{fiifnum0=`}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fiiffalse}fitodayiffalse{fiifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.''
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{iffalse}fi}meaningQ$
%renewenvironment{QQQ}{{iffalse{fi}catcode`&=12 }{{iffalse}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse{fi}executed, not verb|edef|ed{iffalse}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{ifnum0=`}fi}meaningQ$
%renewenvironment{QQQ}{{ifnum0=`{fi}catcode`&=12 }{{ifnum0=`}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`{fi}executed, not verb|edef|ed{ifnum0=`}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
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{fiifnum0=`}fi 1 0 0 0 (GuM suggestion)
Some correlations between my 5-digit grades and this counter table can be established:
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.
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).
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!
tex-core braces
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 iniffalse{fiifnum`}=z@fi
andifnum`{=z@fiiffalse}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 simpleriffalse{fi...iffalse}fi
andifnum0=‘{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 ofiffalse{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}fi
actually produces a score of11110
(awesome!!), whereas the case ofifnum0=‘{fiiffalse}fi...iffalse{fiifnum0=‘}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
|
show 2 more comments
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 1000
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 1110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 0110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 0001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}meaning Q
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
The grade is a 4-digit number, each successive digit describing a "do or not do" to 4 questions:
gets a 1 if the brace method protects inner alignment groups (
A/OK
vs.BAD ALIGNMENT
)gets a 1 if surrounding math atoms can communicate their presence through the boundary (
A = B
vs.A=B
)gets a 1 if an inner macro definition is preserved outside of the grouping (
macro:-> XYZ
vs.undefined
)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:
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)
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{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}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:
The case of no delimiters and brace
{...}
delimiters were complementary, with grades of01110
and10001
, respectively.the case of
iffalse{fi...iffalse}fi
and{iffalse}fi...iffalse{fi}
were complementary, with grades of11100
and00011
, respectively.The case of
ifnum0=‘{fi...ifnum0=‘}fi
and{ifnum0=‘}fi...ifnum0=‘{fi}
were complementary, with grades of01100
and10011
, respectively.The remaining two cases,
bgroup...egroup
andbegingroup...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 were00010
and01010
.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 anedef
.
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|...| (absence of delimiters)hfill Grade 01110
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 10001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{today}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbgrouptodayegroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 11100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fitodayiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 01100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fitodayifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 00011
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse}fitodayiffalse{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`}fitodayifnum0=`{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbegingrouptodayendgroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fiifnum0=`}fi...ifnum0=`{fiiffalse}fi|hfill
Grade 11110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiifnum0=`}fiblech{A&OK}ifnum0=`{fiiffalse}fi
end{aligned}$hfill
$Aiffalse{fiifnum0=`}fi=ifnum0=`{fiiffalse}fi B$
hfill$iffalse{fiifnum0=`}fidefQ{XYZ}ifnum0=`{fiiffalse}fimeaningQ$
renewenvironment{QQQ}{iffalse{fiifnum0=`}ficatcode`&=12 }{ifnum0=`{fiiffalse}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fiifnum0=`}fitodayifnum0=`{fiiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clearpage
{LARGEbfseries 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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fiiffalse}fi...iffalse{fiifnum0=`}fi|hfill
Grade 01110
$begin{aligned}
y&=mx + b\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiiffalse}fiblech{A&OK}iffalse{fiifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fiiffalse}fi=iffalse{fiifnum0=`}fi B$
hfill$ifnum0=`{fiiffalse}fidefQ{XYZ}iffalse{fiifnum0=`}fimeaningQ$
renewenvironment{QQQ}{ifnum0=`{fiiffalse}ficatcode`&=12 }{iffalse{fiifnum0=`}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fiiffalse}fitodayiffalse{fiifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.''
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{iffalse}fi}meaningQ$
%renewenvironment{QQQ}{{iffalse{fi}catcode`&=12 }{{iffalse}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse{fi}executed, not verb|edef|ed{iffalse}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{ifnum0=`}fi}meaningQ$
%renewenvironment{QQQ}{{ifnum0=`{fi}catcode`&=12 }{{ifnum0=`}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`{fi}executed, not verb|edef|ed{ifnum0=`}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
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{fiifnum0=`}fi 1 0 0 0 (GuM suggestion)
Some correlations between my 5-digit grades and this counter table can be established:
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.
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).
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!
tex-core braces
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 1000
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 1110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 0110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 0001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}meaning Q
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
The grade is a 4-digit number, each successive digit describing a "do or not do" to 4 questions:
gets a 1 if the brace method protects inner alignment groups (
A/OK
vs.BAD ALIGNMENT
)gets a 1 if surrounding math atoms can communicate their presence through the boundary (
A = B
vs.A=B
)gets a 1 if an inner macro definition is preserved outside of the grouping (
macro:-> XYZ
vs.undefined
)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:
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)
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{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}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:
The case of no delimiters and brace
{...}
delimiters were complementary, with grades of01110
and10001
, respectively.the case of
iffalse{fi...iffalse}fi
and{iffalse}fi...iffalse{fi}
were complementary, with grades of11100
and00011
, respectively.The case of
ifnum0=‘{fi...ifnum0=‘}fi
and{ifnum0=‘}fi...ifnum0=‘{fi}
were complementary, with grades of01100
and10011
, respectively.The remaining two cases,
bgroup...egroup
andbegingroup...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 were00010
and01010
.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 anedef
.
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}{}{}
defblech#1{blechaux#1relax}
defblechaux#1relax{#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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|...| (absence of delimiters)hfill Grade 01110
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{...}|hfill Grade 10001
$begin{aligned}
y&=mx + b\
E&=mc^2
+ {blech{A&OK}}
end{aligned}$hfill
$A{=}B$hfill${defQ{XYZ}}meaningQ$
%renewenvironment{QQQ}{{catcode`&=12 }{}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{today}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%bgroupblech{A&OK}egroup
end{aligned}$hfill
$Abgroup=egroup B$hfill$bgroupdefQ{XYZ}egroupmeaningQ$
renewenvironment{QQQ}{bgroupcatcode`&=12 }{egroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbgrouptodayegroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fi...iffalse}fi|hfill Grade 11100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiblech{A&OK}iffalse}fi
end{aligned}$hfill
$Aiffalse{fi=iffalse}fi B$hfill$iffalse{fidefQ{XYZ}iffalse}fimeaningQ$
%renewenvironment{QQQ}{iffalse{ficatcode`&=12 }{iffalse}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fitodayiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fi...ifnum0=`}fi|hfill Grade 01100
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiblech{A&OK}ifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fi=ifnum0=`}fi B$hfill$ifnum0=`{fidefQ{XYZ}ifnum0=`}fimeaningQ$
%renewenvironment{QQQ}{ifnum0=`{ficatcode`&=12 }{ifnum0=`}fi}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fitodayifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|{iffalse}fi...iffalse{fi}|hfill Grade 00011
$begin{aligned}
y&=mx + b\
E&=mc^2
+ textrm{BAD ALIGNMENT}% {iffalse}fiblech{A&OK}iffalse{fi}
end{aligned}$hfill
$A{iffalse}fi=iffalse{fi} B$hfill${iffalse}fidefQ{XYZ}iffalse{fi}meaningQ$
renewenvironment{QQQ}{{iffalse}ficatcode`&=12 }{iffalse{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse}fitodayiffalse{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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=`}fiblech{A&OK}ifnum0=`{fi}
end{aligned}$hfill
$A{ifnum0=`}fi=ifnum0=`{fi}B$hfill${ifnum0=`}fidefQ{XYZ}ifnum0=`{fi}meaningQ$
renewenvironment{QQQ}{{ifnum0=`}ficatcode`&=12 }{ifnum0=`{fi}}
begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`}fitodayifnum0=`{fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}%begingroupblech{A&OK}endgroup}
end{aligned}$hfill
$Abegingroup=endgroup B$hfill$begingroupdefQ{XYZ}endgroupmeaningQ$
renewenvironment{QQQ}{begingroupcatcode`&=12 }{endgroup}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQbegingrouptodayendgroup[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|iffalse{fiifnum0=`}fi...ifnum0=`{fiiffalse}fi|hfill
Grade 11110
$begin{aligned}
y&=mx + b\
E&=mc^2
+ iffalse{fiifnum0=`}fiblech{A&OK}ifnum0=`{fiiffalse}fi
end{aligned}$hfill
$Aiffalse{fiifnum0=`}fi=ifnum0=`{fiiffalse}fi B$
hfill$iffalse{fiifnum0=`}fidefQ{XYZ}ifnum0=`{fiiffalse}fimeaningQ$
renewenvironment{QQQ}{iffalse{fiifnum0=`}ficatcode`&=12 }{ifnum0=`{fiiffalse}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQiffalse{fiifnum0=`}fitodayifnum0=`{fiiffalse}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clearpage
{LARGEbfseries 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.
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$bullet$Case verb|ifnum0=`{fiiffalse}fi...iffalse{fiifnum0=`}fi|hfill
Grade 01110
$begin{aligned}
y&=mx + b\
E&=mc^2
% DOES NOT PROTECT INNER ALIGNMENT TAB
+ textrm{BAD ALIGNMENT}%ifnum0=`{fiiffalse}fiblech{A&OK}iffalse{fiifnum0=`}fi
end{aligned}$hfill
$Aifnum0=`{fiiffalse}fi=iffalse{fiifnum0=`}fi B$
hfill$ifnum0=`{fiiffalse}fidefQ{XYZ}iffalse{fiifnum0=`}fimeaningQ$
renewenvironment{QQQ}{ifnum0=`{fiiffalse}ficatcode`&=12 }{iffalse{fiifnum0=`}fi}
begin{QQQ}&&&end{QQQ}
hfill CAN'T EDEF%edefQQifnum0=`{fiiffalse}fitodayiffalse{fiifnum0=`}fi[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.''
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{iffalse}fi}meaningQ$
%renewenvironment{QQQ}{{iffalse{fi}catcode`&=12 }{{iffalse}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{iffalse{fi}executed, not verb|edef|ed{iffalse}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$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}defQ{XYZ}{ifnum0=`}fi}meaningQ$
%renewenvironment{QQQ}{{ifnum0=`{fi}catcode`&=12 }{{ifnum0=`}fi}}
BAD ENV. DEFINITION%begin{QQQ}&&&end{QQQ}
hfilledefQQ{ifnum0=`{fi}executed, not verb|edef|ed{ifnum0=`}fi}[QQ]
noindenthrulefill%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end{document}
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{fiifnum0=`}fi 1 0 0 0 (GuM suggestion)
Some correlations between my 5-digit grades and this counter table can be established:
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.
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).
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!
tex-core braces
tex-core braces
edited Mar 6 '18 at 17:54
Steven B. Segletes
asked Mar 5 '18 at 20:23
Steven B. SegletesSteven B. Segletes
155k9200409
155k9200409
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 iniffalse{fiifnum`}=z@fi
andifnum`{=z@fiiffalse}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 simpleriffalse{fi...iffalse}fi
andifnum0=‘{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 ofiffalse{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}fi
actually produces a score of11110
(awesome!!), whereas the case ofifnum0=‘{fiiffalse}fi...iffalse{fiifnum0=‘}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
|
show 2 more comments
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 iniffalse{fiifnum`}=z@fi
andifnum`{=z@fiiffalse}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 simpleriffalse{fi...iffalse}fi
andifnum0=‘{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 ofiffalse{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}fi
actually produces a score of11110
(awesome!!), whereas the case ofifnum0=‘{fiiffalse}fi...iffalse{fiifnum0=‘}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
5
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
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
2
I don’t understand exactly where you want to get with this, but perhaps you should also take an interest in
iffalse{fiifnum`}=z@fi
and ifnum`{=z@fiiffalse}fi
.– GuM
Mar 6 '18 at 8:42
I don’t understand exactly where you want to get with this, but perhaps you should also take an interest in
iffalse{fiifnum`}=z@fi
and ifnum`{=z@fiiffalse}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
@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
@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
1
@GuM As Marcel notes, the case of
iffalse{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}fi
actually produces a score of 11110
(awesome!!), whereas the case of ifnum0=‘{fiiffalse}fi...iffalse{fiifnum0=‘}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
@GuM As Marcel notes, the case of
iffalse{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}fi
actually produces a score of 11110
(awesome!!), whereas the case of ifnum0=‘{fiiffalse}fi...iffalse{fiifnum0=‘}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
|
show 2 more comments
2 Answers
2
active
oldest
votes
The fourth case is actually 0110, the 1110 came from a typo in the code:
Your test
E&=mc^2
+ {ifnum0=`}fiblech{A&OK}ifnum0=`{fi}
is the test for the sixth case, it should be
E&=mc^2
+ ifnum0=`{fiblech{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:
- Can be used to delimit the definition of an
edef
.
This will fail for bgroup...egroup
, because in
edefsomethingbgroup ABCegroup
bgroup ABCegroup
is interpreted as the parameter text, while there is no problem with
edefsomething{iffalse}fi ABCiffalse{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
add a comment |
Perhaps I should add some explanation about the iffalse{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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@fiiffalse}fi ... iffalse{fiifnum`}=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
&
(orcr
) 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
renewcommandensureTABstackMath[1]{%
iffalse{fiifnum`}=z@fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@TABmode
ifnum`{=z@fiiffalse}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
renewcommandensureTABstackMath[1]{%
iffalse{fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@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@fiiffalse}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{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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{fiifnum0=`}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.
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.
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
andifnum0=`{}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 theifnum0=`{}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
forMH_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
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "85"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f418621%2funderstanding-brace-hacks%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The fourth case is actually 0110, the 1110 came from a typo in the code:
Your test
E&=mc^2
+ {ifnum0=`}fiblech{A&OK}ifnum0=`{fi}
is the test for the sixth case, it should be
E&=mc^2
+ ifnum0=`{fiblech{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:
- Can be used to delimit the definition of an
edef
.
This will fail for bgroup...egroup
, because in
edefsomethingbgroup ABCegroup
bgroup ABCegroup
is interpreted as the parameter text, while there is no problem with
edefsomething{iffalse}fi ABCiffalse{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
add a comment |
The fourth case is actually 0110, the 1110 came from a typo in the code:
Your test
E&=mc^2
+ {ifnum0=`}fiblech{A&OK}ifnum0=`{fi}
is the test for the sixth case, it should be
E&=mc^2
+ ifnum0=`{fiblech{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:
- Can be used to delimit the definition of an
edef
.
This will fail for bgroup...egroup
, because in
edefsomethingbgroup ABCegroup
bgroup ABCegroup
is interpreted as the parameter text, while there is no problem with
edefsomething{iffalse}fi ABCiffalse{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
add a comment |
The fourth case is actually 0110, the 1110 came from a typo in the code:
Your test
E&=mc^2
+ {ifnum0=`}fiblech{A&OK}ifnum0=`{fi}
is the test for the sixth case, it should be
E&=mc^2
+ ifnum0=`{fiblech{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:
- Can be used to delimit the definition of an
edef
.
This will fail for bgroup...egroup
, because in
edefsomethingbgroup ABCegroup
bgroup ABCegroup
is interpreted as the parameter text, while there is no problem with
edefsomething{iffalse}fi ABCiffalse{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
.
The fourth case is actually 0110, the 1110 came from a typo in the code:
Your test
E&=mc^2
+ {ifnum0=`}fiblech{A&OK}ifnum0=`{fi}
is the test for the sixth case, it should be
E&=mc^2
+ ifnum0=`{fiblech{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:
- Can be used to delimit the definition of an
edef
.
This will fail for bgroup...egroup
, because in
edefsomethingbgroup ABCegroup
bgroup ABCegroup
is interpreted as the parameter text, while there is no problem with
edefsomething{iffalse}fi ABCiffalse{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
.
answered Mar 6 '18 at 9:21
Marcel KrügerMarcel Krüger
11.9k11535
11.9k11535
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
add a comment |
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
Thank you for pointing out the typo! I will edit my question to reflect that.
– Steven B. Segletes
Mar 6 '18 at 11:29
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
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
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
6
+1 for the EDEF environment. Impressive!
– Phelype Oleinik
Mar 6 '18 at 12:24
+1 for the EDEF environment. Impressive!
– Phelype Oleinik
Mar 6 '18 at 12:24
add a comment |
Perhaps I should add some explanation about the iffalse{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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@fiiffalse}fi ... iffalse{fiifnum`}=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
&
(orcr
) 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
renewcommandensureTABstackMath[1]{%
iffalse{fiifnum`}=z@fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@TABmode
ifnum`{=z@fiiffalse}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
renewcommandensureTABstackMath[1]{%
iffalse{fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@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@fiiffalse}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{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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{fiifnum0=`}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.
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.
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
andifnum0=`{}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 theifnum0=`{}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
forMH_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
add a comment |
Perhaps I should add some explanation about the iffalse{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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@fiiffalse}fi ... iffalse{fiifnum`}=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
&
(orcr
) 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
renewcommandensureTABstackMath[1]{%
iffalse{fiifnum`}=z@fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@TABmode
ifnum`{=z@fiiffalse}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
renewcommandensureTABstackMath[1]{%
iffalse{fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@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@fiiffalse}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{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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{fiifnum0=`}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.
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.
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
andifnum0=`{}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 theifnum0=`{}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
forMH_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
add a comment |
Perhaps I should add some explanation about the iffalse{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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@fiiffalse}fi ... iffalse{fiifnum`}=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
&
(orcr
) 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
renewcommandensureTABstackMath[1]{%
iffalse{fiifnum`}=z@fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@TABmode
ifnum`{=z@fiiffalse}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
renewcommandensureTABstackMath[1]{%
iffalse{fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@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@fiiffalse}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{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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{fiifnum0=`}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.
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.
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
andifnum0=`{}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 theifnum0=`{}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
forMH_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!).
Perhaps I should add some explanation about the iffalse{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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@fiiffalse}fi ... iffalse{fiifnum`}=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
&
(orcr
) 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
renewcommandensureTABstackMath[1]{%
iffalse{fiifnum`}=z@fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@TABmode
ifnum`{=z@fiiffalse}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
renewcommandensureTABstackMath[1]{%
iffalse{fi
letsv@TABmodeTAB@delimTABstackMath#1letTAB@delimsv@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@fiiffalse}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{fiifnum`}=z@fi ... ifnum`{=z@fiiffalse}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{fiifnum0=`}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.
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.
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
andifnum0=`{}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 theifnum0=`{}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
forMH_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!).
edited Feb 10 at 0:59
answered Mar 6 '18 at 21:27
GuMGuM
16.6k2457
16.6k2457
1
Thank you for taking the time to add your expertise to the mix.
– Steven B. Segletes
Mar 7 '18 at 0:25
add a comment |
1
Thank you for taking the time to add your expertise to the mix.
– Steven B. Segletes
Mar 7 '18 at 0:25
1
1
Thank you for taking the time to add your expertise to the mix.
– Steven B. Segletes
Mar 7 '18 at 0:25
Thank you for taking the time to add your expertise to the mix.
– Steven B. Segletes
Mar 7 '18 at 0:25
add a comment |
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f418621%2funderstanding-brace-hacks%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
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{fiifnum`}=z@fi
andifnum`{=z@fiiffalse}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 simpleriffalse{fi...iffalse}fi
andifnum0=‘{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{fiifnum0=‘}fi...ifnum0=‘{fiiffalse}fi
actually produces a score of11110
(awesome!!), whereas the case ofifnum0=‘{fiiffalse}fi...iffalse{fiifnum0=‘}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