5

I'm trying to set a conditional \if... to true or false based on another condition. Something similar to this:

\documentclass{article}

\newif\iffirst

\iftrue
  \let\iffirst\iftrue% ... similar to \firsttrue
\else
  \let\iffirst\iffalse% ... similar to \firstfalse
\fi

\begin{document}

\iffirst
  First
\else
  Not first
\fi

\end{document}

The output logically should be First, since \iffirst is set to \iftrue. However, it doesn't work. Why not? I thought once the condition is evaluated (\iftrue or \iffalse), it executes the true/false clause, with \let<cmdA><cmdB> being valid.

Instead of \let\iffirst\iftrue/\let\iffirst\iffalse, one can use \firsttrue/\firstfalse. However, these both have the same meaning (that is, \show\firsttrue reveals \let\iffirst\iftrue and similarly \show\firstfalse reveals \let\iffirst\iffalse). So, why does \firsttrue/\firstfalse work, but specifying \let\iffirst\iftrue/\let\iffirst\iffalse explicitly doesn't?

The following workaround also helps but doesn't answer the question:

\documentclass{article}

\newcommand{\firstoftwo}[2]{#1}% Similar to \@firstoftwo
\newcommand{\secondoftwo}[2]{#2}% Similar to \@secondoftwo

\iftrue
  \let\firstsecond\firstoftwo
\else
  \let\firstsecond\secondoftwo
\fi

\begin{document}

\firstsecond{%
  First
}{%
  Not first
}

\end{document}

1 Answer 1

6

TeX doesn't look at the syntax of your code when skipping \if..\else..\fi blocks, so it doesn't know that \let should consume two tokens. This means that in \let\iffirst\iftrue (with \iffirst being equal to \iffalse) you have two \if but no \fi, so when TeX tries to balance them it doesn't do what you expect. Re-indenting your code based on what TeX sees, it looks like this:

\iftrue % \if level 1
  \let\iffirst\iftrue
\else % \else level 1
  \let
  \iffirst % \if level 2
    \iffalse % \if level 3
    \fi % \fi level 3

which is obviously wrong. When executing the code, the \iftrue (\if level 1) is true, so the \let\iffirst\iftrue is executed. Then \else is seen, and TeX starts looking for a \fi level 1, but here \iffirst and \iffalse are misinterpreted and two \fi are missing.

A good way to work around this when setting the conditional is to first completely evaluate the \iftrue..\else..\fi block, and only then do \let\iffirst\if<something>, then you make sure that neither is interpreted as starting another \if level (this is roughly how expl3 conditionals are implemented, so they can be easily nested without worrying about balancing \if..\else..\fi):

\documentclass{article}

\newif\iffirst

\makeatletter
\iftrue
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi
  {\let\iffirst\iftrue}%
  {\let\iffirst\iffalse}%
\makeatother

\begin{document}

\iffirst
  First
\else
  Not first
\fi

\end{document}

This feature, of not looking at the meaning of the code when balancing conditionals, allows the Dirty Tricks with braces presented in Appendix D. Here's an example of an apparently unbalanced code, which actually works correctly (and note that text is not printed in bold face):

{\bfseries
  bold
  \iffalse {\fi }
  text

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .