13

I have this MWE, which does not compile (Extra \else, Extra \fi) unless I load the showlabels package before the outer \if. (\ifSL@AMS is defined in showlabels.sty.) Is that a general requirement that I have so far never violated, or am I coming up to some special case here? It seems so be pretty general, because my second MWE fails the exact same way.

\documentclass{article}
%\RequirePackage{showlabels}

\makeatletter
\newif\ifsomething
\ifsomething
    \RequirePackage{showlabels}
    \ifSL@AMS
    \else
    \fi
\else
\fi
\begin{document}
    X
\end{document}

and

\documentclass{article}
\newif\ifA
\ifA
    \newif\ifB
    \ifB
    \else
    \fi
\else
\fi
\begin{document}
    AB
\end{document}
11

Heiko’s answer is a little terse, so I hope that I will be allowed to add a few words of explanation, even if I do not propose an alternative solution.

I would say that the answer to your question is “it depends on whether the outer switch is true or false”. I’ll analyze your second example, that deals with \ifA and \ifB, in order to explain why Heiko’s answer works.

If TeX finds that the outer \ifA is false, it will begin to skip tokens until it finds the corresponding \else or \fi; while doing so, if it runs into a control sequence that has already been defined as a conditional, it keeps track that it starts a new, nested conditional. But when TeX has begun to skip tokens, that is, immediately after the \ifA, the control sequence \ifB was not yet known to represent a conditional; thus, TeX simply skips over it like over any other token, and when it comes to the ensuing \else, it thinks that this is the \else it was looking for, that is, the one which goes with \ifA, and so it resumes executing tokens. The next token is \fi, which is interpreted as the end of the \ifA conditional. As you can now see, the following \else is obviously misplaced in TeX’s eyes.

On the other hand, everything goes fine if the outer \ifA switch is true, because in this case TeX executes the definition of \ifB before seeing it. You can try this yourself:

\documentclass{article}
\newif\ifA
\Atrue
\ifA
    \newif\ifB
    \ifB
    \else
    \fi
\else
\fi
\begin{document}
    AB
\end{document}

The reason why Heiko’s answer works is, of course, that TeX always knows that \ifx is a conditional. So, even if it is skipping over the “true branch” of \ifA, it can tell that the first \else, and the ensuing \fi, should be paired with \ifx and not with \ifA.


Addition

A comment suggests that I should further clarify the matter.

Yes, the usual paradigms you may be accustomed to when thinking of programming languages aren’t appropriate for TeX: TeX is different, and it probably shouldn’t be even considered a programming language, but rather a purely sequential processor equipped with a very powerful macro preprocessor; with a crucial feature, however: that the meaning of macros can be defined, and changed, at run-time.

Coming to our specific case, there is no built-in “syntactic” rule that dictates that control sequences starting with \if... are conditionals: this is merely a convention that should be adhered to, but nothing more. (Note, however, that plain TeX’s \newif enforces it; LaTeX2e’s doesn’t, but assumes that the “core” of the name of the conditional is preceded by a two-letter prefix.) As far as the “machine level” of TeX is concerned, there are only a finite number of conditionals: for Knuth’s original TeX3, they are the 14 control sequences listed on pages 209–210 of The TeXbook, namely

  • \ifnum,

  • \ifdim,

  • \ifodd,

  • \ifvmode,

  • \ifhmode,

  • \ifmmode,

  • \ifinner,

  • \if,

  • \ifcat,

  • \ifx,

  • \ifvoid,

  • \ifeof,

  • \iftrue, and

  • \iffalse

(there is also the \ifcase primitive, but it is quite different from the others). Other typesetting engines (e-TeX, pdfTeX, and so on) add many other primitive conditionals to this list, each of them having its peculiar list of additions, but it remains true that only the control sequences explicitly belonging to these finite lists of primitives can act as a conditional, and in particular are recognized as such when skipping over tokens belonging to a branch of an (outer) conditional that hasn’t been taken.

How can we define new, “custom” conditionals, then? Well, as already said above, the macro processor included in TeX has the peculiar characteristic that the meaning of macros can be changed at run-time, and this is how the ability to define new conditionals is attained. Let’s see in detail how this works by means of an example.

When you say

\newif\ifFOO

the following things happen:

  1. First, the equivalent of

    \let\ifFOO=\iffalse
    

    is executed. So, the control sequence \ifFOO is made a perfect synonym of \iffalse; in particular, from now on TeX will recognize \ifFOO as a conditional (unless, or until, it is redefined, of course), even when skipping over tokens at high speed.

  2. Two new control sequences \FOOtrue and \FOOfalse are defined, with a meaning equivalent to that given them by the following code:

    \def\FOOfalse{\let\ifFOO=\iffalse}
    \def\FOOtrue {\let\ifFOO=\iftrue}
    

So, you can now say, for example

\FOOtrue

in some place of your code, and that will make subsequent occurrences of \ifFOO behave exactly as \iftrue had been written in their place; and similarly for \FOOfalse.

I hope that this suffices to clarify how \if... conditionals work.

  • Thanks. I am still trying to wrap my head around "the control sequence \ifB was not yet known to represent a conditional". I had always assumed that, as in many other languages, syntax parsing and actual interpretation are two separate steps; for example in C++, int a = {}; is syntactically correct and only fails to compile. So I expected TeX to know that any \if... is a conditional without me having to define it as such. But maybe the answer to that is simply that TeX does not parse the document before compilation. – bers Jun 21 '16 at 20:17
  • 1
    @bers: Please see update. – GuM Jun 22 '16 at 0:52
  • Beautifully explained! – bers Jun 22 '16 at 0:55
13

\else and \fi are already defined. But if the starting \ifSL@AMS is not defined, then TeX will not recognize the undefined control sequence as \if... switch and the \if..., \else, and \fi tokens are not properly nested anymore.

Workaround:

\makeatletter
\newif\ifsomething
\ifsomething
    \RequirePackage{showlabels}
    \expandafter\ifx\csname ifSL@AMS\expandafter\endcsname\csname iftrue\endcsname
    \else
    \fi
\else
\fi
\makeatother

Here \ifx is defined and the two command sequences, which are compared, are not yet visible, but will be build, when the branch with \ifx is actually executed.

  • Thank you for that workaround! I take your answer as a "yes, it is a general thing" even without you explicitly mentioning it :) – bers Jun 20 '16 at 19:21
7

Assuming \ifsomething returns false, the “true” text is skipped, except that TeX still balances conditionals. Since \ifSL@AMS is not defined, it is skipped, but then \else is matched to \ifsomething and you end up with an “Extra \else”.

This is a good place for using ifthen:

\RequirePackage{xifthen} % or ifthen

\ifthenelse{\boolean{something}}
  {% true branch of \ifsomething
   \RequirePackage{showlabels}%
   \ifthenelse{\boolean{SL@AMS}}
     {% true branch of \ifSL@AMS
      % whatever
     }
     {% false branch of \ifSL@AMS
      % whatever
     }%
  {% false branch of \ifsomething
   % whatever
  }
  • xifthen... never heard of it. Just a guess: it uses the syntax of ifthen package, but maybe uses etoolbox internals to better avoid pathological cases?? – Steven B. Segletes Jun 20 '16 at 20:24
  • @StevenB.Segletes It's an improvement of ifthen; etoolbox is not involved. – egreg Jun 20 '16 at 20:26
  • 2
    How could that be possible? – David Carlisle Jun 20 '16 at 22:17

Your Answer

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

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