From: MJD@MATH.AMS.ORG (Michael Downes)
Newsgroups: comp.text.tex
Subject: Re:  Problems with false conditionals
Date: 26 Jan 93 15:09:25 GMT
Organization: Info-Tex<==>Comp.Text.Tex Gateway
X-Gateway-Source-Info: Mailing List

Michael Barr wrote:

> The following four lines cause an error:
> \iffalse
> \newif\iftest
> \fi
> \bye
>
> On the other hand, these four don't:
> \iftrue
> \newif\iftest
> \fi
> \bye

\newif is defined to be \outer in plain TeX. From the TeXbook, p. 206:

  An \outer macro cannot appear in an argument (not even when \par is
  allowed), nor can it appear in the parameter text or the replacement
  text of a definition, nor in the preamble to an alignment, nor in
  conditional text that is being skipped over.  If an \outer macro
  does show up in such places, TeX stops what it is doing and reports
  either a ``runaway'' situation or an ``incomplete'' conditional.

> I am trying to do something with conditional compilation.  So I defined
> a \newif that can be set true or false to determine which of two paths
> to follow.  The problem is that the false path included the use of a
> macro named \ifnnull (if non-null) that included an \if in its
> definition and in use was to be complemented by a \fi.  Here is a
> simplified version of what it all looked like:
>
> \newif\ifTotOnly
> \TotOnlytrue
>
> \def\ifnnull#1{\def\next{#1}\ifx\next\empty\else}
>
> \ifTotOnly
> %%%% Next line cases trouble when \TotOnlyfalse:
> \newif\ifnnull
>
> %% stuff when \TotOnlytrue
>
> \else
>
>
> %% stuff when \TotOnlyfalse that uses \ifnnull ... \fi
>
> \fi
>
> %% rest of file

...

> I think the correct explanation is really the same
> thing that led me to this kludge in the first place: the parser sees
> \ifnnull as an \if, even when it is just being defined.

No, TeX is stopping at the \newif, it has not yet considered the
\ifnnull. If you want to put a \newif inside a conditional,
\csname newif\endcsname will work whether the condition is true or
false.

> But it does not
> see it as an \if when it is just a control sequence.

That's right, only the primitive \if's---or control sequences that are
equated to one of them with \let---are recognized by TeX's conditional
scanning. Conditionals created by \newif are always equal to either
\iftrue or \iffalse.

If you want a conditional that includes non-expandable statements in
its definition (such as "\def\next{#1}") there is a trick suggested by
Knuth in TeXhax a few years ago (in response to a query of Stephan von
Bechtolsheim):

  \def\nnull#1{TT\fi \def\next{#1}\ifx\next\empty\else}

Usage:

  \if\nnull{abc}...\fi

Explanation: This uses the primitive \if at the surface level to
satisfy TeX's scanner. If the entire \if\nnull...\fi construction
occurs on the false branch of an enclosing conditional, TeX sees only
the \if and \fi and does not look inside \nnull. If the \if is
actually executed, the TT\fi will match the \if and the \ifx will
match the following \fi.

Or try the LaTeX-style construction \ifnonnull{...}{true case}{false
case}.

  \def\ifnonnull#1#2#3{\def\truecase{#2}\def\falsecase{#3}%
    \def\next{#1}%
    \ifx\next\empty \let\next\truecase
    \else \let\next\falsecase
    \fi
    \next
  }

This has the advantage that the true or false case can end with
a macro that requires arguments. (With the other style of conditional,
such a macro would try to use the \else or \fi as an argument, with
laughable results.)

The LaTeX convention of putting in an @ at the beginning (i.e.
\@ifnonnull) is recommended for non-\newif-created macros like this
since the lack of a \fi will otherwise make it impossible for a smart
text editor to help you properly match up \if \else \fi for the
standard kinds of conditionals. (Or some other distinguishing
convention, perhaps \IFnonnull or \nonnullp.) And if you are starting
to do more complex conditional programming as your example suggests, I
suspect you will soon wish for such a matching ability in your text
editor.

Michael Downes                              mjd@math.ams.org (Internet)