Reset counter via macro with \ifcase in Plain

I am not able to reset a counter to zero using a macro in Plain TeX.

This code uses \ifcase and the counter animalnum to output one of a list of animal names, incrementing the counter each time it is called so that next call will produce the subsequent name in the list. If it has been called more than a maximum number, it outputs an error message.

The command \resetanimalnum is supposed to set the counter back to zero and start the list over, but for some reason it doesn't work as expected.

Why does the counter behave this way and I how can I fix it?

\newcount\animalnum

\def\nextanimal{%
\ifcase\animalnum%
\animalI\or
\animalII\or
\animalIII%
\fi%
\ifnum\animalnum > 2
\exclaim%
\fi%
}

\def\resetanimalnum{\animalnum=0}

\def\animalI   {Lions}
\def\animalII  {Tigers}
\def\animalIII {Bears}
\def\exclaim   {Oh my!}

\nextanimal\ \nextanimal\ \nextanimal\ \nextanimal

\resetanimalnum\nextanimal\ \nextanimal

\bye


• I think, \resetanimalnum is the culprit. If you put \nextanimal into the next line, it works – user31729 Jan 14 '16 at 19:13
• try \def\resetanimalnum{\animalnum=0\relax} – touhami Jan 14 '16 at 19:13
• you can replace \fi% \ifnum\animalnum > 2 with \else – touhami Jan 14 '16 at 19:14
• if tex is trying to determine the value of a counter, it keeps going until it definitively finds something non-numeric. so a space or \relax will stop the parsing of \animalnum=0. – barbara beeton Jan 14 '16 at 19:26
• There are a number of references to this on the site. Here's one which includes a reference elsewhere as well: Use of \relax after \ifnum\fi construction – Werner Jan 14 '16 at 19:38

the main culprits are the incorrect use of % after the 1 which prevents the 1 being terminated, and the lack of a space after 0. In some cases you can terminate a number with \relax but that leaves a \relax in the token stream which is not always desirable, a space is absorbed as part of the number.

\newcount\animalnum

\def\nextanimal{%
\ifcase\animalnum
\animalI\or
\animalII\or
\animalIII
\fi
\ifnum\animalnum > 2
\exclaim
\fi
}

\def\resetanimalnum{\animalnum=0 }

\def\animalI   {Lions}
\def\animalII  {Tigers}
\def\animalIII {Bears}
\def\exclaim   {Oh my!}

\nextanimal\ \nextanimal\ \nextanimal\ \nextanimal

\resetanimalnum\nextanimal\ \nextanimal

\bye

• Thank you -- this explains it completely. Is it also true that I should more properly use \else instead of the \ifnum construction? – musarithmia Jan 14 '16 at 20:56
• @AndrewCashner I saw that comment on the other answer but they are not equivalent so it depends what you want if you go ifcase or, or, or ...else fiexclaim then you either get an animal or exclaim. if you go ifcase of or or fi \ifnum exclaim fi then you get an animal and then exclaim if the test number is bigger than 2 so you may get an animal and an exclaim – David Carlisle Jan 14 '16 at 21:13

It's stated (somehow) in the TeX by Topic book (page 66)

TeX can expand too far in case of counter evaluation and will try find something non-numerical, i.e. it might absorb and expand the next statement \nextanimal which is a fault here.

If \relax is inserted, this can be stopped. (The \relax is not mentioned on that page, but the expansion can be stopped with \relax then.

A one-time solution would be to place a newline between \resetanimalnum and the next call to \nextanimal, but this might get tedious.

\newcount\animalnum

\def\nextanimal{%
\ifcase\animalnum%
\animalI\or
\animalII\or
\animalIII%
\fi%
\ifnum\animalnum > 2
\exclaim%
\fi%
}

\def\resetanimalnum{\animalnum=0\relax}%

\def\animalI   {Lions}
\def\animalII  {Tigers}
\def\animalIII {Bears}
\def\exclaim   {Oh my!}

\nextanimal\ \nextanimal\ \nextanimal\ \nextanimal

\resetanimalnum\nextanimal\ \nextanimal

\bye


• \ifcase\animalnum<0>\or<1>\or<2>\else\exclaim\fi is “more correct”. – Manuel Jan 14 '16 at 19:45