# Stopping the accidental absorption of digits into literals

I recall that I was once writing some TeX code, and I encountered something like this

\count\foo
\foo=2\otherMacro
[\the\foo]


If \otherMacro was defined as something like \def\otherMacro{9 cats is too many} then \foo in the above line would actually get set to 29 instead of 2, because the 9 from the cats macro would be absorbed.

A more insidious case is something like this:

\newcount\foo
\def\setfoo{\foo=2}
\def\otherMacro{9 cats is too many}
\setfoo\otherMacro
[\the\foo]


This code also goes awry and absorbs the 9, setting \foo to 29. In this case it's harder to know where the appropriate place for the fix is. And it's hard to see the error when looking at \setfoo\otherMacro without also going back to the macro definitions, because in real-world cases the macro definitions will probably be very far away from the invocations.

I remember that at the time I ran into this issue I sat down and developed a comprehensive understanding of all of the cases where this would happen, and I adopted a set of defensive coding standards to prevent it, which involved liberal use of % and spacing. However, I didn't take any notes, and I'm not confident that I can remember all of the details and nuances. For example, I can't recall whether or not this ever happened when dealing with \dimen or other types of registers, and I can't recall exactly what my rules were for the defensive use of % and spacing.

I'm about to sit down to experiment with this TeX-gotcha once again, but I figured that it couldn't hurt to also post to SO for community advice. I know that SO doesn't usually like discussion threads, so I'll put it like this instead: If anybody has a comprehensive understanding of these issues, then a single-post brain dump on the matter would make for a solid SO-appropriate response.

Note also that I'm using Plain TeX, and not LaTeX.

[UPDATE]:

After considering suggested solutions from David Carlisle, and considering the caveats which he described, I'm amending this curiosity to this post:

\def\otherMacro{9 cats is too many}
\newcount\foo
\def\bar#1{[\the\foo][#1]}

\def\setfooSpace{\foo=2 }
\def\setfooRelax{\foo=2\relax}

\afterassignment\bar\setfooSpace\otherMacro

\afterassignment\bar\setfooRelax\otherMacro


The second-to-last line results in the text

[2][9 cats is too many]


while the last line itself results in

[2][]9 cats is too many


Both the \relax and the 2<space>solutions work to prevent the absorption of the 9 into the 2, but the solution with the space appears to be superior in that it makes a macro like \setfoo feel more atomic.

-
Related: Consistent typography – Werner Jul 23 '14 at 23:31
The TeXbook, page 208: For best results, always put a blank space after a numeric constant; this blank space tells TeX that the constant is complete, and such a space will never “get through” to the output. – egreg Jul 23 '14 at 23:35

A space following a digit always terminates the <number> and is absorbed so

\foo=2 \otherMacro


would assign 2 to \foo followed (with no space) by the expansion of \othermacro

Any other non expandable non digit token terminates the <number> but is replaced so

\foo=2\relax\otherMacro


assigns 2 to \foo then the token stream has \relax and the expansion of \otherMacro

In any other case the token following the digit is expanded to decide if their are more tokens to be absorbed into the number.

\def\setfoo{\foo=2}


is a bug waiting to happen and should be

\def\setfoo{\foo=2 }


or of course

\def\setfoo{\foo=\tw@}


a major reasons for tokens such as \tw@ is to avoid these problems as they are complete <number> (defined with \chardef in that case) so TeX does not scan ahead looking for more digits.

-
Wow, great, I think that basically covers it. Though I'm left wondering if \relax, the space, and the \chardef methods are any different, or if they're all precisely identical. Specifically, I recall that \relax has some sort of side effects, and that it sometimes puts TeX into a special sort of state, which the space or the \chardef might not. I could be wrong though, since my understanding of \relax is fuzzy. – patrick-rutkowski Jul 23 '14 at 23:51
@patrick-rutkowski assuming the assignment happens (ie you don't have \@gobble\foo=2 etc then \tw@ and 2  are similar (except the first is faster) but 2\relax leaves  \relax token in the input stream since the assignment isn't expandable it's not so easy to come up with places that makes a different but \afterassignment\bar\foo=2\relax\othermacro \bar will see \relax but \afterassiggment\bar\foo=2\othermacro it will see \othermacro` – David Carlisle Jul 23 '14 at 23:57