The definition of \@gobble
is equivalent to
\newcommand{\@gobble}[1]{}
so, when used, it will simply throw away its argument. When you say something like
\let\macro\@gobble
you're telling TeX that \macro
will throw away its argument. Instead
\@gobble{something}
throws away {something}
as soon as TeX finds it.
Let's see the code you're referring to:
\long\def\savedata#1{%
\setbox0\vbox\bgroup
\let\\\cr
\let\midrule\@empty
\let\multicolumn\@gobbletwo
\everyeof{\noexpand}%
\halign\bgroup
\global\colc\z@
\global\advance\rowc\@ne\@gobble{##}&&%
\global\advance\colc\@ne
\expandafter\xdef\csname data-#1(\the\rowc,\the\colc)\endcsname
{\zap@space## \@empty}\cr
\@@input #1
\crcr\egroup\egroup}
Its purpose is to load a file (the argument to \savedata
) which contains what usually would go between \begin{tabular}{l...}
and \end{tabular}
, in order to gather data from it.
The table is typeset inside a box, which will not be used afterwards (\setbox0=\vbox\bgroup
) and in this box, which forms a group, some macros are redefined: \let\\\cr
and \let\midrule\@empty
. The first is to make \\
into the simple table line terminator, the second is because \midrule
is meaningless for the purpose. Also \multicolumn
is redefined:
\let\multicolumn\@gobbletwo
so that, when TeX will see \multicolumn{1}{c}{(1)}
it will leave only {(1)}
in the input stream, because \@gobbletwo
looks for two arguments and doesn't do anything with them, so they simply disappear. Probably
\let\multicolumn\@thirdofthree
would be theoretically better, but in the end the result is just the same. Can you see now why? Your input file will possibly contain \multicolumn
, but in this context we are only interested in the third argument, because we are not really typesetting a table, but only storing its contents (cell by cell) in macros.
A technically important \everyeof{\noexpand}
is issued (I won't discuss it) and then a \halign
is opened.
The syntax for the primitive \halign
is quite interesting; I'm not going into the details, but basically it is
\halign{<template>\cr
<table row>\cr
...
<table row>\cr
}
where <template>
is a collection of specifications for each table column in the form <before>#<after>
and separated by &
. The #
represents the cell contents. A &&
sequence means that the following specifications are repeated as many times as the table needs.
In this case the template is
\global\colc\z@
\global\advance\rowc\@ne\@gobble{##}&&%
\global\advance\colc\@ne
\expandafter\xdef\csname data-#1(\the\rowc,\the\colc)\endcsname
{\zap@space## \@empty}\cr
which specifies a first column where the counter representing the columns is set to 0 and the one representing rows is advanced by one. Then the cell contents is passed to \@gobble
, so it will vanish, as we don't need it.
The rest of the table is a sequence of columns with the following specification: the column counter is stepped and macros of the form
\data-<argument>(i,j)
(<argument>
is the argument to \savedata
, in parentheses are the row and column indices, as numbers; the macro name can't be written with ordinary means, but \csname...\endcsname
allows for those strange characters in the name). The replacement text for this macro provides eventually the cell contents with leading and trailing spaces removed (\zap@space## \@empty
). The \cr
ends the template.
As Ahmed Musa remarks, the \zap@space
macro should be used with care, because it zaps all spaces; in this case it's unimportant, because the significant entries don't contain spaces.
Finally the table contents is input so that the macros will be defined; \\
will be translated into the primitive \cr
to provide line terminations (the more complex job that \\
does in LaTeX tabular
environments is not needed here) and \multicol{1}{c}{(1)}
will leave only {(1)}
.
The table is terminated by \crcr
which will not add a line if the code ends with \\
. The first \egroup
matches the \bgroup
after \halign
and the second one the \bgroup
after \vbox
.
Note that here the "cell contents placeholder", ordinarily #
, has to be doubled because we are inside a definition.
Best Answer
What's happening in your sample code is that first, you create a box of 10mm width having some glue at both ends and a letter in the middle. The glue is set, within the box, so that the whole space is filled. Then you unbox it. The contents are emptied into the main horizontal list, and the glue is reset in that context. The error you are getting is
which comes about when TeX starts trying to reset the infinitely-shrinkable
\hss
(this despite the fact that it only needs to expand, and you can see in the output that the letter a is indeed centered on its line).The situation with your new example is exactly the same. If you place a whole box into a paragraph, then regardless of the glue in it, there will be no infinite shrinkage because the glue is already set in the box. If you unbox it, then the glue loses its dimensions and has to be reset, and its infinite shrink component gives an error.
Perhaps it is best to think of the situation as follows. Let
.
denote glue and let-
denote set glue; i.e. actual space. I'll write an actual box with bars|
. Then you have the following correspondence:First the
\hbox
examines the horizontal list inside, which includes glue, and sets the length of that glue so that it fills the box, resulting in the last picture. Suppose that's the box stored in\box0
. Then your example is:You see, when the bars are removed, the
-
's revert to.
's and have to be reinterpreted, leading to some different lengths, as shown at right. The problem is that even though those lengths are stretched, the glue itself has an infinite shrink component, and this is not allowed in a computation outside an\hbox
.