# Is it a bad practice to declare variables locally inside macros or environments?

For me, declaring variables globally will clutter the project. Especially when there are many variables to be declared.

In addition, declaring variables locally will save our time because we don't need to make sure whether the variables have been declared.

I don't know whether it is a bad practice in TeX.

\documentclass{minimal}

\newcommand\Average[5]{%
\newcount\Total%
\Total\numexpr#1+#2+#3+#4+#5\relax%
\number\numexpr\Total/5\relax%
}

\begin{document}
The average of 1, 2, 3, 4, 5 is \Average{1}{2}{3}{4}{5}.
\end{document}

-
@xport. The two cases are actually different. If you give me ten minutes, I'll have something on my blog about this, which I might then rephrase into an answer :-) –  Joseph Wright Dec 30 '10 at 17:42
@Joseph, OK. \(^.^)/ –  xport Dec 30 '10 at 17:46
Using \newcount inside \Average is a very bad idea. Better use one of the scratch counters of the latex kernel, e.g. \@tempcnta. Or define your own scratch counter which you will use in all your commands. –  Ulrike Fischer Dec 30 '10 at 18:02
@Ulrike, why is it a bad idea? –  xport Dec 30 '10 at 18:17
@xport: The inside of a macro is not a group, so in fact, your definition is not local. Every call of \Average in fact allocates a different counter, so after up to 255 (but in practice fewer) calls in the same document, you get an error. At least, with the original TeX. –  Ryan Reich Dec 30 '10 at 18:48

I've examined this in a bit more detail in my blog, but for the purposes of answering the question I'll do a bit of editing and post the key points here.

First, the standard \newcount, \newtoks, etc., functions allocate globally. So something like

\begingroup
\newcount\mycount
\endgroup


will permanently consume a register, even though \mycount disappears at the end of the group. The etex package provides \loccount, \loctoks, etc., which do free up the allocation at the end of a group. So

\begingroup
\loccount\mycount
\endgroup


is at least not going to consume registers. However, there are other issues.

In most languages, a local variable is local to some function, and nested functions have there own independent local variables. In TeX, things are different, as it is a macro language and only grouping makes things local. So something like

\def\BadIdea{%
\loccount\mycount
...
}


will not destroy \mycount at the end of the material inserted by \BadIdea. On the other hand, things will work within a group, so doing

\def\BetterIdea{%
\begingroup
\loccount\mycount
....
\endgroup
}


will destroy \mycount as expected. However, you'd get much the same effect by doing

\newcount\mycount
\def\BetterIdea{%
\begingroup
....
\endgroup
}


or even (if you know it's safe)

\def\BetterIdea{%
\begingroup
\@tempcnta=<value>
....
\endgroup
}


i.e. using the general scratch registers.

As local variables for TeX are about groups, and not about macros, I think that best practice remains to allocate globally and use locally. With my LaTeX3 'hat' on, I'd point out that we did try some local allocations out, and when we worked things through decided it was a bit of a nightmare.

-
@Joseph: what you wrote depends to TeX counters but LaTeX counters used with the LaTeX commands for setting and using behave differently to TeX counters –  Herbert Dec 30 '10 at 19:00
@Herbert. Not really: they are TeX counts, after all. Of course, if you use \setcounter then the allocation is global, but one can create a counter using LaTeX and then set it using TeX. (As the discussion was about local variables, then I've assumed we are talking about the low-level registers rather than any higher-level interface). –  Joseph Wright Dec 30 '10 at 19:29
@Joseph: One area that would really benefit from being able to deallocate is \newread/\newwrite. Since there are so few, it would be great to allocate one, use it, and then deallocate it. –  TH. Dec 30 '10 at 19:33
@TH. That's exactly what we've done in the LaTeX3 code: there is a pool of writes (and reads), and they are deallocated when not in use. I'm wondering about going even further, and only providing some kind of 'intermediate' interface, but at present haven't got a good plan for \shipout stuff. The problem is that this can be applied to new code but can't simply be 'retro-fitted' to existing packages. –  Joseph Wright Dec 30 '10 at 19:38
@TH. I think this might be one for another blog post, at least looking at why the issue comes up and potential alternative approaches. –  Joseph Wright Dec 30 '10 at 19:52