7

Since \newsavebox{\name} assigns the box register number to \name, there are probably a maximum of 256 boxes available. Is there a way to release a \savebox after you are through with it?

6
  • 3
    You can set the contents of the box as many times as you want.
    – egreg
    Jun 16, 2014 at 15:29
  • 3
    Also most people use an etex based format in which case there are 32768 rather than 256 box registers Jun 16, 2014 at 15:34
  • 2
    You have the temporary boxes available to you: \setbox0=\hbox{...} then \box0 to output it. Depending on your application, these could serve and be constantly reused. Jun 16, 2014 at 15:45
  • @Steven B. Segletes - How many are temporary and how many are reserved by \newsavebox? My guess would be that box0 - box25 are temporary. Jun 18, 2014 at 20:08
  • @JohnKormylo I've always assumed that all temporary boxes are subject to destruction if left unattended long enough. In fact, Knuth points out that the use of \boxn causes \boxn to become void (i.e., it loses its contents). So I don't know the answer to your question, sad to say. I did just learn that \copyn uses box n without destroying it. Interesting... Jun 18, 2014 at 20:36

3 Answers 3

9

The normal model is to allocate a box once (before the document starts) and use it multiple times in whatever macro is being defined, so the limit is not usually a problem, however all modern distributions use an etex based format for LaTeX in which case there are 32768 registers available (although you need \usepackage{etex} to declare that to latex and to use an allocation scheme that knows about the registers.

3
  • 4
    We should integrate etex into the kernel, like I said :-)
    – Joseph Wright
    Jun 16, 2014 at 16:09
  • 1
    @JosephWright I could hear you as I posted the above:-) Jun 16, 2014 at 16:13
  • 1
    I understand the current thinking in computer science is to deliberately make programs as bloated and slow as possible so as to force people to buy new computers. ;-) Jun 17, 2014 at 12:56
7

As mentioned by others, LaTeX doesn't provide a way to free up unused registers. It's bit more difficult that your example code suggests since you could add `holes' to the list of allocated registers that you'd need to fill; keeping track of them would be awkward or slow.

If you find yourself needing to use many many registers that you would like to free up, etex.sty has `local' register allocation under the macros

  • \loccount
  • \locdimen
  • \locskip
  • \locmuskip
  • \locbox
  • \loctoks
  • \locmarks

An example is shown following; you can see that the same box gets allocated twice under different names.

\documentclass[a4paper]{article}
\usepackage{etex}
\begin{document}

\begingroup
\locbox\textbox
\savebox\textbox{this is box \the\textbox: some text}
\fbox{\usebox\textbox}
\endgroup

\begingroup
\locbox\textboxB
\savebox\textboxB{this is box \the\textboxB: some more text}
\fbox{\usebox\textboxB}
\endgroup

\end{document}

To be effective you'll need grouping, but if you have such a prodigious need for save boxes then you'll probably be grouping at some level anyway.

5
  • We've steered away from offering local allocators in expl3 because of inconsistencies with edge cases with token lists (specifically, if you globally assign to a local register, it still disappears, but if you globally assign to a local macro, it stays). But if we assumed that all \g_ tls must be allocated globally and all \l_ must be allocated locally, we would be okay (and this is also recommended in TeX for performance reasons). So with sufficient interest this matter could probably be revived again... Jun 17, 2014 at 3:21
  • If you remember, the other problem was that as TeX's group model requires explicit groups, it looked as if creating local registers could lead to a lot of confusion.
    – Joseph Wright
    Jun 17, 2014 at 5:53
  • @JosephWright — Looks like I don't remember :) We can discuss elsewhere, perhaps. Jun 17, 2014 at 8:32
  • BTW, is there an etex compatible macro to use instead of \chardef (like maybe \boxdef)? Jun 18, 2014 at 19:59
  • @JohnKormylo Not sure exactly what you mean — if you need larger values than \chardef allows you can use \mathchardef. \boxdef sounds like it would just be \newbox wouldn't it? Jun 19, 2014 at 4:27
1

If you use a temporary box register (like \box0) you must make sure that no macros are called which use the same box, and you must hope that no updated version or package replacement will ever use it either. However if you use \newsavebox, then it is safe from anyone else using \newsavebox (until you release it with \freebox).

\documentclass{article}

\makeatletter
\newcounter{free@boxes}% push stack counter
\newcounter{free@count}% loop counter

\global\let\old@savebox=\newsavebox% save original version

\global\chardef\free@min 255
\global\chardef\free@max 0

\newcommand*{\freebox}[1]% #1 = old savebox name
{\newif\ifgood\goodtrue%
\ifnum#1<\free@min \goodfalse\fi%
\ifnum#1>\free@max \goodfalse\fi%
\ifnum\value{free@boxes}=0\relax%
  \else\setcounter{free@count}{\value{free@boxes}}%
  \loop% check for duplicates
    \ifnum#1=\csname free@box\arabic{free@count}\endcsname
      \goodfalse%
      \setcounter{free@count}{0}%
    \else\addtocounter{free@count}{-1}\fi%
    \ifnum\value{free@count}>0 \repeat%
  \fi %
\ifgood\stepcounter{free@boxes}%
\global\expandafter\let\csname free@box\arabic{free@boxes}\endcsname#1%
\fi%
\global\chardef#1 0}

\renewcommand*{\newsavebox}[1]{% #1 = new savebox name
\ifnum\value{free@boxes}>0%
  \global\edef#1{\csname free@box\arabic{free@boxes}\endcsname}%
  \addtocounter{free@boxes}{-1}%
\else\old@savebox{#1}%
  \ifnum#1<\free@min \global\let\free@min=#1 \fi%
  \ifnum#1>\free@max \global\let\free@max=#1 \fi%
\fi}
\makeatother

\begin{document}
\newsavebox{\test}
\savebox{\test}{This is a test}
\usebox{\test}

\newsavebox{\testb}
\savebox{\testb}{This is the second test}
\usebox{\testb}

\freebox{\test}% release box registers for reuse
\freebox{\testb}

\newsavebox{\reuseb}% push stack returns second box first
\usebox{\reuseb}

\newsavebox{\reuse}
\usebox{\reuse}

The following have been reset to zero:\newline
\verb$\test$ \the\test\newline
\verb$\testb$ \the\testb

\makeatletter
The following should all equal the first box register value:\newline
\verb$\reuse$ \the\reuse\newline
\verb$\free@box1$ \the\csname free@box1\endcsname

The following should all equal the second box register value:\newline
\verb$\reuseb$ \the\reuseb\newline
\verb$\free@box2$ \the\csname free@box2\endcsname
\makeatother

\end{document}
9
  • 1
    Is this intended as an answer or a comment on the question? but why the complication, why not simply use the same box both times? Jun 16, 2014 at 17:52
  • I can find no sense in this, sorry.
    – egreg
    Jun 16, 2014 at 18:04
  • @David Carlisle - The idea is that different macros by different authors could reuse the same box registers. Instead of trying to keep track of which boxes are still being used and which are not, this does it for you. Of course, it would work better to replace \newsavebox than introduce a new command \resusesavebox. Jun 17, 2014 at 1:22
  • @JohnKormylo I can't see a use case for this, either the box is only used in a controlled local scope in which case there is no need to allocate one you can use a scratch box such as 0 or 2 or 4 or \@tempboxa, or it needs to save box data across macros potentially from another package in which case you have nowhere to deallocate as you need to know the box has not been used when you come to use the saved value. Jun 17, 2014 at 9:12
  • @David Carlisle - The goal was not to use the contents of a previously filled savebox. This was just a test program to verify that it was working. Jun 17, 2014 at 12:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .