Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Another strangeness in conditionals

29 views
Skip to first unread message

GL

unread,
May 20, 2013, 8:06:19 PM5/20/13
to
Hello,

Comparing :

\iftrue true\else false\or ok\fi % no problem: \or is ignored

\ifcase 1 \or \else \or \fi % no problem: \or is ignored

\iffalse false\or error\else ok\fi % error : ???

Thanks if so has a clue.


Ulrich D i e z

unread,
May 21, 2013, 6:30:47 AM5/21/13
to
Actually I don't have a clue.

To me it seems that chapter 20 of the TeXbook almost says
that <true>-branches that are to be skipped can end by \else,
\or or \fi while the token ending the branch will be carried out.
(So the <true>-branch of the \iffalse-construct ends by \or and TeX
raises an error-message when carrying out an \or which
does not belong to an \ifcase-statement...) :

| Now let's consider the control sequences that are expanded
| whenever expansion has not been inhibited. Such control
| sequences fall into several classes:
[...]
| - Conditionals. When an \if... is expanded, TeX reads ahead
| as far as necessary to determine whether the condition is true
| or false; and if false, it skips ahead (keeping track of \if..\fi nesting)
| until finding the \else, \or or \fi that ends the skipped text.
| Similarly, when \else, \or or \fi is expanded, TeX reads to the
| end of any text that ought to be skipped. The "expansion" of a
| conditional is empty. (Conditionaly always reduce the number of
| tokens that are seen by later stages of the digestive process, while
| macros usually increase the number of tokens.)


To me it seems that the speech in the former paragraph is not
very clear.

- E.g., the second sentence of that paragraph indicates that
_conditions_ can have determinable truth-values (true/false).
(In the former paragraphs of that chapter, the term
"conditional commands" is used.)
It is not conditions but it is "statements about conditions being
fulfilled/ not being fulfilled" that might have truth values and determining
these truth values means determining whether these statements are
"in accord with facts and/or reality".

- There are no clear statements about the set of tokens suitable
for ending text that ought to be skipped when \else, \or or \fi is
expanded.



Why does the following not produce any output at all?

\ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
\bye


Ulrich

Enrico Gregorio

unread,
May 21, 2013, 9:11:52 AM5/21/13
to
My understanding is that when the conditional is false,
TeX skips tokens until finding the matching \else. In
the third case, it finds a misplaced \or /before/ finding
the matching \else, so it raises an error.

Conversely, when TeX expands \else, it just skips to the
matching \fi.

Why did Knuth choose so, I don't know.


> Why does the following not produce any output at all?
>
> \ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
> \bye

Good question!

Ciao
Enrico

GL

unread,
May 21, 2013, 11:56:05 AM5/21/13
to
Le 21/05/2013 15:11, Enrico Gregorio a ÔøΩcrit :
>
> My understanding is that when the conditional is false,
> TeX skips tokens until finding the matching \else. In
> the third case, it finds a misplaced \or /before/ finding
> the matching \else, so it raises an error.

Right.

> Conversely, when TeX expands \else, it just skips to the
> matching \fi.

Not really since :

\ifcase 2 zero \or one \else other \or error\fi % throws an error

So that the \else of \ifcase does not behave like the \else of \iftrue :

\iftrue true\else false \or ok \fi % OK.

GL

unread,
May 21, 2013, 11:58:10 AM5/21/13
to
Le 21/05/2013 17:56, GL a ÔøΩcrit :
> Le 21/05/2013 15:11, Enrico Gregorio a ÔøΩcrit :
>>
>> My understanding is that when the conditional is false,
>> TeX skips tokens until finding the matching \else. In
>> the third case, it finds a misplaced \or /before/ finding
>> the matching \else, so it raises an error.
>
> Right.
>
>> Conversely, when TeX expands \else, it just skips to the
>> matching \fi.
>
> Not really since :
>
> \ifcase 2 zero \or one \else other \or error\fi % throws an error
>

Sorry : the \else part is actually executed in this case and the
error is hopefully expected.

GL

unread,
May 21, 2013, 12:01:06 PM5/21/13
to
Le 21/05/2013 12:30, Ulrich D i e z a �crit :
The log says :

{\ifcase: (level 1) entered on line 33}
{\iffalse: (level 2) entered on line 33}
{false}
{\else: \iffalse (level 2) entered on line 33}
{case 1}
{\or: \iffalse (level 2) entered on line 33}
{\else: \iffalse (level 2) entered on line 33}
{\fi: \iffalse (level 2) entered on line 33}
{\fi: \ifcase (level 1) entered on line 33}


{\or: \iffalse and e-TeX seems happy !}

Very weird ! Thanks.

Ulrich D i e z

unread,
May 22, 2013, 3:22:12 AM5/22/13
to
GL wrote:

> Le 21/05/2013 12:30, Ulrich D i e z a �crit :
[...]
> > Why does the following not produce any output at all?
> >
> > \ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
> > \bye
>
> The log says :
>
> {\ifcase: (level 1) entered on line 33}
> {\iffalse: (level 2) entered on line 33}
> {false}
> {\else: \iffalse (level 2) entered on line 33}
> {case 1}
> {\or: \iffalse (level 2) entered on line 33}
> {\else: \iffalse (level 2) entered on line 33}
> {\fi: \iffalse (level 2) entered on line 33}
> {\fi: \ifcase (level 1) entered on line 33}
>
>
> {\or: \iffalse and e-TeX seems happy !}
>
> Very weird ! Thanks.

Indeed. I expected the above to evaluate to the result that
_one_ gets with:

\expandafter\ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
\bye

(Same as above but leading \expandafter attached...)

Sincerely

Ulrich

GL

unread,
May 22, 2013, 7:21:38 AM5/22/13
to
Le 22/05/2013 09:22, Ulrich D i e z a �crit :
Yes this is exactly the same since \ifcase<number> expands everything
until it can evaluate <number> : \expandafter is useless here.

(a) \ifcase\iffalse 0\else 1 zero\else larger\else test\fi \fi
=> no error

all the same :
(b) \ifnum 0=\iffalse 0\else 1 zero\else larger\fi \fi

(c) But :\ifnum 1=\iffalse 0\else 1 zero\else larger\fi \fi

leads to an error : "extra \else"

This is because \else is both a delimiter and a command :

* As a delimiter, \else is checked by TeX to decide if it corresponds
to the very conditional that asked for an \else.
If so, it simply disappears updating the "currentifbranch".
the delimiter is "gobbled": \else branch to be executed.
If not, it is simply ignored and not executed as a command.
in true words: it does nothing.

* As a command, it is checked by TeX to decide if it is an
"extra \else" or not.
If not, \else is executed, looking forward for a matching \fi delimiter
that corresponds to the very conditional that asked for \fi.


This explains the noticed behaviour :

Case (b) for memory: \ifnum 0=\iffalse 0\else 1 zero\else larger\fi \fi

The first expansion is: \ifnum 0=1 zeros\else larger\fi \fi

\ifnum (false) goes until to the /delimiter/ \else which is
checked as "\else (iffalse)" since \iffalse is the nested
active conditional and therefore, \ifnum ignores it (nested
\else that don't correspond to \ifnum) : \else does nothing
and \ifnum still requires a matching \else (or \fi) and looks
forward for another candidate : it its way it sees the delimiter
\fi which is checked as \fi (iffalse) and is executed (end of the
nested conditional : "currentiflevel--")
but \ifnum is still requiring its matching \else (or \fi)
and looks forward, finds \fi which is checked as \fi (\ifnum)
and is executed ("currentiflevel--").

Case (a) is the same:
for memory \ifcase\iffalse 0\else 1 zero\else larger\else test\fi \fi

\ifcase evaluates to {case 1} and looks for the matching /delimiter/
\or (or \else or \fi ) and finds \else which is checked as \else
(iffalse) and ignored by \ifcase as a nested conditional : \else really
does nothing at all and \ifcase goes further still looking for a
matching \or, \else or \fi and finds \else again which is checked
as \else (iffalse) for the same reason and does nothing. Thus \ifcase
is still requiring a matching \or or \else (or \fi) and looks forward
again and reaches \fi which as a delimiter is checked as \fi (iffalse)
and executed ("currentiflevel--") and \ifcase is still requiring its
matching stuff, looking forward until to \fi, checked as \fi (\ifcase)
and executed as such ("currentiflevel--").

In case (c):
for memory \ifnum 1=\iffalse 0\else 1 \else larger\else error\fi \fi

First expansion: \ifnum 1=1 \else larger\else error\fi \fi

\ifnum evaluates to true and disappears then \else is executed as a
command : it is checked to be \else (iffalse) which is an error since
\else (iffalse) has been executed (currentifbranch is -1).

Regards

Ulrich D i e z

unread,
May 22, 2013, 12:23:19 PM5/22/13
to
At first I thought so, but the results differ:

\ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
\bye

-> No pages of output at all. No error-messages.

\expandafter\ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
\bye

-> A page of output, containing the word "one". No error-messages.

Sincerely

Ulrich

GL

unread,
May 22, 2013, 12:49:13 PM5/22/13
to
Le 22/05/2013 18:23, Ulrich D i e z a �crit :
>>
>> Yes this is exactly the same since \ifcase<number> expands everything
>> until it can evaluate <number> : \expandafter is useless here.
>
> At first I thought so, but the results differ:
>
> \ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
> \bye
>
> -> No pages of output at all. No error-messages.
>
> \expandafter\ifcase\iffalse 0\else1 zero\or one\else larger\fi\fi
> \bye
>
> -> A page of output, containing the word "one". No error-messages.

Right. (sorry i didn't test before). This does not change anything
to the "explanation" i tempted previously : here the effect of
\expandafter is that the first expansion becomes :

\ifcase1 zero\or one\else larger\fi \fi

so that \ifcase is executed after \iffalse, and therefore,
\ifcase increases "currentiflevel++" and looks forward for
a match \or (or possibly \else or \fi).

When \or is reached, it is checked to be "\or (\ifcase)"
(since \ifcase is the current "iflevel" at that time) and
TeX expands <<one>> then finds \else which is executed as a
command : \else is first checked to be "\else (\ifcase)"
(because the current "iflevel" is the one of \ifcase at that time)
and looks forward for \fi which is checked as "\fi (\ifcase)" and
executed as such ("currentiflevel--") and then the execution of the
last \fi [ "\fi (\iffalse)" because the current "iflevel" is the one of
\iffalse ] closes the whole conditional ("currentiflevel--" again).

\expandafter carries \ifcase after the first \else in the expression.

Thanks for your interesting example.
Regards.
0 new messages