How does this TeX code generate automatic \hline's in tabular environments?
Breaking the code
\catcode`@=11
\let \savecr \@tabularcr
\def\@tabularcr{\savecr\hline}
\catcode`@=12
down step-by-step:
\catcode`@=11
This changes the category code for
@
to 'letter', since@
may otherwise not be used inside macro names. You'll note that the subsequent line uses\@tabularcr
, for which we need@
to be of type 'letter'. Others like to use\makeatletter
for this (see What do\makeatletter
and\makeatother
do?).\let \savecr \@tabularcr
This makes an immediate copy of
\@tabularcr
and stores it in\savecr
. It allows you to now modify\@tabularcr
(subsequent line) yet still have a copy of the older version.\def\@tabularcr{\savecr\hline}
Here
\@tabularcr
is actually redefined to be\savecr
(stored above as a copy of\@tabularcr
before this redefinition followed by\hline
- the horizontal rule you're after. Why (re)define\@tabularcr
? From the LaTeX kernel (latex.ltx
), the definition of thetabular
environment executes (at some later stage)\def\@tabular{\leavevmode \hbox \bgroup $\let\@acol\@tabacol \let\@classz\@tabclassz \let\@classiv\@tabclassiv \let\\\@tabularcr\@tabarray}
Here you can see (in the last line) that
\\
is set to be equivalent to\@tabularcr
before starting the actualtabular
, so\\
will have the new definition of\@tabularcr
which now includes an appended\hline
.\catcode`@=12
This restores the category code of
@
to other. Some users prefer using\makeatother
.
For a reference on what category codes are, see What are category codes?
Of course, the addition of this before a tabular
makes it global within your document. It's perhaps more wise to contain this within a group (or as an environment) to localize the change. Alternatively, you can define command switches to "activate" this \hline
automation and "deactivate" it later.
That code seems to work, but it doesn't. Let's look at an example:
\documentclass{article}
\catcode`@=11
\let \savecr \@tabularcr
\def\@tabularcr{\savecr\hline}
\catcode`@=12
\begin{document}
\begin{tabular}{c}
a\\[1cm]
b
\end{tabular}
\end{document}
that outputs
Let's see why. The original definition of \@tabularcr
is
% latex.ltx, line 5040:
\def\@tabularcr{%
{\ifnum0=`}\fi\@ifstar\@xtabularcr\@xtabularcr}
and already something is to be noted: if one, by mistake or because some code is being shared between tabular
and longtable
, types \\*
for ending a row, the *
will not be recognized and removed by the redefined command, because the token after \savecr
is always \hline
.
So the new \@tabularcr
leaves in the input stream
\@xtabularcr\hline
and here's where things go wrong again, because the definition of \@xtabularcr
is
% latex.ltx, line 5042:
\def\@xtabularcr{\@ifnextchar[\@argtabularcr{\ifnum0=`{\fi}\cr}}
The token next to \@xtabularcr
will never be [
, and this is the cause for the bad output of my example.
What's the best way to automatically add a rule after every row? None, for at least two reasons:
- Horizontal rules are not necessary after every row.
- You can't add
\cline
where you need it.