Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have found that when saving and later using boxes the box with index 10 behaves differently to all other.

Here is simple demo that shows different behaviour. In preamble I define this commands:

\usepackage{forloop}
\newcounter{BoxCount}
\newcommand{\numberedBox}[1]{%
  \stepcounter{BoxCount}%
  \savebox{\theBoxCount}{\vbox{\noindent\theBoxCount\\~ #1}}%
}%
\newcommand{\writeBoxes}{
  \stepcounter{BoxCount}%
  \newcounter{I}%
  \setcounter{I}{1}%
  \forloop{I}{1}{\value{I} < \value{BoxCount}}{%
  \usebox{\theI}\par
}%

The \numbredBox basically stores given text in indexed box while adding number of the box to the text. The \writeBoxes prints all stored boxes in order they were stored.

In document body I have this code:

\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\numberedBox{word}
\writeBoxes

This is printed output of this document: enter image description here All the boxes are printed as expected except for 10th box which somehow interfere with box 11. I have played with similar code a little and found out that 10th saved almost always box behaves strange. In some cases I even got ! Incompatible list can't be unboxed error but only for 10th saved box (content of all the boxes was equal).

Why is this happening? How can I avoid it?


EDIT

Here is complete source of this example that Hebert asked for. Just compile with pdfLaTeX and you will get output shown above.

\documentclass[a5paper]{book}
\usepackage{forloop}
\newcounter{BoxCount}
\newcommand{\numberedBox}[1]{%
  \stepcounter{BoxCount}%
  \savebox{\theBoxCount}{\vbox{\noindent\theBoxCount\\~ #1}}%
}%
\newcommand{\writeBoxes}{
  \stepcounter{BoxCount}%
  \newcounter{I}%
  \setcounter{I}{1}%
  \forloop{I}{1}{\value{I} < \value{BoxCount}}{%
    \usebox{\theI}\par
  }%
}
\begin{document}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \writeBoxes
\end{document}
share|improve this question
    
give a complete example. –  Herbert Jan 15 '13 at 12:02
    
@Herbert The code that was there was almost complete - except for document class, begin and end of the document. Nevertheless I have added complete source, please see my edit. –  drasto Jan 15 '13 at 12:10
    
no, I couldn't see how you define the boxes –  Herbert Jan 15 '13 at 12:30
    
@Herbert I just use numbers as their names and so I don't need to define them. I take it (from egreg's answer) that I'm in the fact using Tex registers for storing boxes. –  drasto Jan 15 '13 at 12:37
    
As Herbert says, your code doesn't declare the boxes - there is no \newsavebox. Also, if add a \tracingassigns=1, or just \showbox11, you will see that \box11 is not void when you define it, so it is being used by something else. –  Andrew Swann Jan 15 '13 at 12:38
show 5 more comments

2 Answers

up vote 11 down vote accepted

use the LaTeX definition of boxes:

\documentclass[a5paper]{book}
\usepackage{forloop}
\newcounter{BoxCount}
\setcounter{BoxCount}{0}
\newcounter{I}
\newcommand\numberedBox[1]{%
  \stepcounter{BoxCount}%
  \expandafter\newsavebox\expandafter{\csname BOX\alph{BoxCount}\endcsname}
  \expandafter\sbox\expandafter{\csname BOX\alph{BoxCount}\endcsname}{\vbox{\noindent\theBoxCount\\~ #1}}%
}%
\newcommand{\writeBoxes}{
  \stepcounter{BoxCount}%
  \setcounter{I}{1}%
  \forloop{I}{1}{\value{I} < \value{BoxCount}}{%
    \usebox{\csname BOX\alph{I}\endcsname}\par
  }%
}
\begin{document}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \writeBoxes
\end{document}

enter image description here

share|improve this answer
add comment

You shouldn't be using box registers by number other than those numbered from 0 to 9.

In particular box register 10 corresponds to \voidb@x which the LaTeX kernel considers as an always empty box. If you fill it with something a number of macros will work wrongly. Among them

\leavevmode
\settowidth \settoheight \settowidth

Why do you get an error? Because \usebox does \leavevmode which in turn does \unhbox\voidb@x; you've set \box10 (that is \voidb@x) to a \vbox, so the command performed by \leavevmode tries to \unhbox a \vbox, which is not allowed.

Here's a safer (but not completely foolproof) way. If it's just for experiments, then it's not so risky; on the other hand I would never use this for real document production. In that case I would allocate my box registers.

\documentclass[a5paper]{book}
\usepackage{forloop,etex}
\newcounter{BoxCount}
\setcounter{BoxCount}{\count14}
\ifnum\value{BoxCount}<256 
  \setcounter{BoxCount}{355}
\else
  \addtocounter{BoxCount}{100}
\fi
\mathchardef\FirstBoxCount=\value{BoxCount}
\newcommand{\numberedBox}[1]{%
  \stepcounter{BoxCount}%
  \savebox{\theBoxCount}{\vbox{\noindent\theBoxCount\\~ #1}}%
}
\newcounter{I}
\newcommand{\writeBoxes}{%
  \stepcounter{BoxCount}%
  \setcounter{I}{\FirstBoxCount}%
  \forloop{I}{1}{\value{I} < \value{BoxCount}}{%
    \usebox{\theI}\par
  }%
}
\begin{document}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \writeBoxes
\end{document}

Using the extended register set and going 100 registers from the last allocated one if the extended register set is already used, this should work without touching any allocated box register.


The LaTeX kernel allocates more box than register 10:

\voidb@x=\box10
\strutbox=\box11
\@tempboxa=\box12
\rootbox=\box13
\@labels=\box14
\@curline=\box15
\@curfield=\box16
\@tabfbox=\box17
\@arstrutbox=\box18
\@picbox=\box19
\@linechar=\box20
\@dashbox=\box21
\@begindvibox=\box22
\@outputbox=\box23
\@leftcolumn=\box24
\@holdpg=\box25

Using these registers and following ones possibly allocated by packages is an almost sure way to make things go wrong. You're shooting your own foot if you do it.


Here is a completely safe version.

\documentclass[a5paper]{book}
\usepackage{forloop,etex}
\newcounter{BoxCount}

\makeatletter
\newcommand{\myBox}[1]{\@nameuse{myBox@\number\value{#1}}}
\newcommand{\checkBox}[1]{%
  \@ifundefined{myBox@\number\value{#1}}
    {\expandafter\newbox\csname myBox@\number\value{#1}\endcsname}
    {}%
}
\makeatother

\newcommand{\numberedBox}[1]{%
  \stepcounter{BoxCount}%
  \checkBox{BoxCount}%
  \savebox{\myBox{BoxCount}}{\vbox{\noindent\theBoxCount\\~ #1}}%
}
\newcounter{I}
\newcommand{\writeBoxes}{%
  \stepcounter{BoxCount}%
  \setcounter{I}{1}%
  \forloop{I}{1}{\value{I} < \value{BoxCount}}{%
    \usebox{\myBox{I}}\par
  }%
}
\begin{document}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \numberedBox{word}
  \writeBoxes
\end{document}

When you set a box associated to a counter's value, you first check for its allocation:

\checkBox{BoxCount}

will allocate a new box register if you haven't done it so far; if the box register is already allocated, nothing happens. Then you use

\myBox{<counter>}

when you need to save or use the box register corresponding to the counter's value.

share|improve this answer
    
+1 So to avoid it I only set initial value of BoxCount to 11? If it works, you are the man! –  drasto Jan 15 '13 at 12:13
    
@drasto Not at all. You're doing damages to other reserved box registers. –  egreg Jan 15 '13 at 12:20
3  
@dastro You should be using a range of boxes you've reserved. Normally, you don't work with box numbers but with names (created using \newbox). You could go for something like \expandafter\newbox\csname mybox@1\endcsname, etc., to give yourself a set of boxes with numbers in the names. –  Joseph Wright Jan 15 '13 at 12:28
    
@Joseph Wright I would like to use box names instead of numbers to not to interfere with Tex registers (I understand now that it is not good practise). Your comment is welcome but it does not show how can I declare box that has name consisting of some letters and value of a counter. I really need to use value of a counter instead of just fixes numbers in boxes names. And I'd like to use LaTeX macro \newsavebox instead of Tex \newbox. If you can show me how to solve this 2 thinks, please do and make it an answer so I can upvote and even accept it. –  drasto Jan 15 '13 at 12:41
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.