# How to write a TeX macro that accepts a number or a \count register as argument?

What's the most simple way, in plain TeX, to define a \macro that can be used as:

\macro{10}

\macro{\mycount}


such that I can then assign the number to a \count and manipulate it?

Note:

\def\macro#1{...\number#1 ...}


is not what I want.

In other words, how can I modify the following TeX code (see ex 10.4 of The TeXbook):

\def\tick#1{\vrule height 0pt depth #1pt}

\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\def\doticks#1{\count255=#1%
\ifnum\count255=1%
\tmp%
\else%
\tmp\doticks\count255%
\fi}

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks\number#1}}}


In such a way that:

\ruler{10}

\count255=10
\ruler{\count255}
\bye


outputs a page with two 10 centimetres rulers drawn on it?

(current code gives a Missing number error).

• I was using \count255 because the TeXbook mentions that it is a scratch register. However I just tried Ian solution and replacing \mycount with \count255 it doesn't work, so some macro in there is using \count255 too... – Bakuriu Nov 13 '13 at 21:20
• @Bakuriu: Note his solution braces the argument for \doticks... which is necessary. – Werner Nov 13 '13 at 21:20
• @Bakuriu, after adding the braces (\doticks{\number#1}), there is also the % in \def\doticks#1{\count255=#1% which is problematic, because the \ifnum test may be expanded before the assignment is done. If you do \expandafter\doticks\expandafter{\number#1} on one hand and on the other hand \def\doticks#1{\count255=#1  without a % (but with a space), the it will be ok. See my upcoming answer for the complete thing (there are other modifications too) – user4686 Nov 13 '13 at 22:04

In addition to @Werner's suggestion of using your own counter, I think you need braces around \number#1, otherwise \doticks picks up \number as its argument.

\def\tick#1{\vrule height 0pt depth #1pt}

\newcount\mycount
\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\def\doticks#1{\mycount=#1%
\ifnum\mycount=1%
\tmp%
\else%
\tmp\doticks\mycount%
\fi}

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{\number#1}}}} % <--- new braces here

\ruler{10}

\mycount=10
\ruler{\mycount}
\bye

• Damn, I lost hours for this and turns out I forgot one pair of braces. I must mention that the use of \newcount seems required. If I copy-paste your solution and replace \mycount with \count255 inside the \doticks macro I still get a Missing number ... error. Next time I'll make sure to avoid even so-called scratch registers... – Bakuriu Nov 13 '13 at 21:24
• If you wish to use \count255, you need to enclose it in braces whenever it is passed to \doticks (there are two locations). – Werner Nov 13 '13 at 21:25
• @Werner Right. I'm probably too affected by programming languages where identifiers are single tokens and can contain digits, while \count255 contains two tokens... From now on until I learn I should really first enclose any argument with braces, and afterwards ask my self if they contain a single token or not and eventually remove them. Maybe doing this I'll finally learn. – Bakuriu Nov 13 '13 at 21:52
• All % in the definition of \doticks are either wrong or redundant. Precisely, the first should be \relax, the second should be removed and the others are redundant. – egreg Nov 13 '13 at 22:26
• @Bakuriu \count255 is 4 tokens not two – David Carlisle Nov 14 '13 at 1:32

Use \afterassignment and a group, so not to clobber the value of \count255. Also use tail recursion.

\def\tick#1{\vrule height 0pt depth #1pt }

\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\def\doticks#1{\begingroup\afterassignment\dodoticks\count255=#1\endgroup}
\def\dodoticks{%
\tmp
\ifnum\count255=1
\let\next\relax
\else
\let\next\dodoticks
\fi
\next
}

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{#1}}}}

\ruler{10}

\count255=10
\ruler{\count255}

\bigskip

{\tt\string\count255} is \number\count255

\bye


The same with some @'s:

\def\tick#1{\vrule height 0pt depth #1pt }

\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\catcode@=11
\def\doticks#1{\begingroup\afterassignment\d@ticks\count@=#1\endgroup}
\def\d@ticks{%
\tmp
\ifnum\count@=\@ne
\let\next\relax
\else
\let\next\d@ticks
\fi
\next
}
\catcode@=12
\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{#1}}}}

\ruler{10}

\count255=10
\ruler{\count255}

\bigskip

{\tt\string\count255} is \number\count255

\bye

• you can optimize your \d@ticks via \ifnum\count@=\@ne\else\advance\count@\m@ne\expandafter\d@ticks\fi (or \ifnum\count@>\@ne etc... which perhaps is faster than testing for equality and then \else. I don't know) – user4686 Nov 14 '13 at 11:38
• @jfbu I used Knuth style tail recursion on purpose. – egreg Nov 14 '13 at 11:51
• I see, I thought \expandafter\stuff\fi was also called tail recursion. Should I delete my comment? – user4686 Nov 14 '13 at 12:12
• @jfbu It is tail recursion: the important thing is that the conditional is removed from the input stream and both methods do it. Actually, removing \let\next\relax and changing \let\next\d@ticks into \expandafter\d@ticks should be more efficient. As I said, I just wanted to do it Knuth-style. – egreg Nov 14 '13 at 12:18

A version without using a temp count register. Requires etex but pdftex includes that by default.

\def\tick#1{\vrule height 0pt depth #1pt}

\def\doticks #1{%
\hbox to 1cm{\hfil\tick4\hfil\tick8}%
\ifnum#1>0
\expandafter\doticks\expandafter{\the\numexpr#1-1\expandafter\relax\expandafter}%
\fi
}

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{#1}}}}

\ruler{10}

\newcount\mycnt

\mycnt=10

\ruler{\mycnt}

\nopagenumbers
\bye

• I'm pretty sure \numexpr is not expandable, so unless you add \number in front of it the first two \expandafter tokens do nothing. – egreg Nov 14 '13 at 10:40
• @egreg, they did something when they were written (as I had \the) seems like I took that out before posting, but left the expandafter:( will fix – David Carlisle Nov 14 '13 at 11:17
• @egreg \the is quicker than \number when prefixing a \numexpr. – user4686 Nov 14 '13 at 11:24
• @DavidCarlisle you don't need the \relax, the closing brace will stop the \numexpr, (after the \expandafter has taken care of the fi). – user4686 Nov 14 '13 at 11:26
• @jfbu yes I know but it's easier to put it there than worry about not needing it (it would be needed if the outer exandafters were removed as then the {} would be macro delimiters and be gone by the time numexpr was evaluated. – David Carlisle Nov 14 '13 at 16:35

You can also do it in the following (not very efficient!) style:

\def\tick#1{\vrule height 0pt depth #1pt}

\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\def\doticks#1{\count255=#1\relax
\ifnum\count255=1
\tmp
\else
\tmp\doticks{\count255 }%
\fi}

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{#1}}}}

\ruler{10}

\count255=5

\ruler{\count255}

\nopagenumbers
\bye


Actually, this code (maybe I should have read it) indeed does nest many \if..\fi so to avoid that, one could do the (somewhat silly but working):

\def\doticks#1{\count255=#1\relax
\tmp
\ifnum\count255=1
\let\next\relax
\else
\def\next {\doticks{\count255 }}%
\fi
\next }


Anyway, there is in the Plain format a loop which it is very natural to use here:

\def\tick#1{\vrule height 0pt depth #1pt}

\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\def\doticks #1{\count255=#1\relax
\loop
\tmp
\ifnum\count255>1
\repeat
}

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{#1}}}}

\ruler{10}

\newcount\mycnt

\mycnt=10

\ruler{\mycnt}

\nopagenumbers
\bye


If one wants to preserve as egreg the value stored in \count 255 one can also do it without creating a group. It is irrelevant for the task at hand, but for other situations it could be useful to not create a group.

(for efficiency one should also do as egreg and use \count@, @ne, m@ne etc...)

\def\tick#1{\vrule height 0pt depth #1pt}

\def\tmp{\hbox to 1cm{\hfil\tick4\hfil\tick8}}

\def\doticks #1{\edef\restorecountxxlv{\count255=\the\count255\relax}%
\count255=#1\relax \dotickticks \restorecountxxlv }

\def\dotickticks{\tmp
\ifnum\count255>1
\expandafter\dotickticks
\fi }

\def\ruler#1{\vbox{\hrule\hbox{\tick8\doticks{#1}}}}

\count255 7

\ruler{10}

{\tt\string\count 255} stores \the\count255

\newcount\cnt
\cnt=3

\ruler{\cnt}

{\tt\string\count 255} stores \the\count255

\bye