14

I have bumped into the \span primitive a couple of time. I got the impression it is defined in the TeX program, not even in plain.tex. Is that right? And what does that command do and what is it for?

  • Just from the name, for me it sounds like some sort of \multicolumn, like \span 3 columns :P – Manuel Sep 27 '14 at 12:30
  • I think it is used in \multirow. I remember reading it was used in \multisomething, but I don't remember if something was row or column :). It is also used in \sp@n, which is LaTeX kernel. – MickG Sep 27 '14 at 12:33
  • Yep, \multicolumn->\multispan->\@multispan->\sp@n->\span. \multirow doesn't use it. – MickG Sep 27 '14 at 12:36
16

The primitive \span has two very different meanings if it appear in the preamble of \halign or in the body.

If it's in the preamble, that is before the first \cr it means “expand” the following token; if it appears in the body it ends the current cell, but merges it with the following one. In this case it's usually in combination with \omit.

The simplest example is

\halign{\hfil#\tabskip1em&#\hfil\cr
  a&b\cr
  c\span d\cr
}

where the second row will have just one cell. The output will be

enter image description here

with no \tabskip spacing between “c” and “d”, because the second row is just one cell with \hfil before and after the contents, but TeX will take the \tabskip into account for determining the cell's width.

Usually, however, one also adds \omit in order to remove the u and v parts (u refers to what comes before #, v to what follows it).

When TeX is reading a preamble for \halign it doesn't expand tokens unless it finds \tabskip (when it expands tokens for finding the appropriate glue specification). Expansion of a token can be forced by preceding it with \span.

An example is in amsmath.sty

\def\align@#1#2{%
    \inalign@true \intertext@ \Let@ \chardef\dspbrk@context\z@
    \ifingather@\else\displ@y@\fi
    \let\math@cr@@@\math@cr@@@align
    \ifxxat@\else \let\tag\tag@in@align \fi
    \let\label\label@in@display
    #1% set st@r
    \ifst@rred\else \global\@eqnswtrue \fi
    \measure@{#2}%
    \global\row@\z@
    \tabskip\eqnshift@
    \halign\bgroup
        \span\align@preamble\crcr
        #2%
}

This is a helper macro used for align and friends; the preamble is defined once and for all in the macro \align@preamble

\def\align@preamble{%
   &\hfil
    \strut@
    \setboxz@h{\@lign$\m@th\displaystyle{##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \tabskip\z@skip
   &\setboxz@h{\@lign$\m@th\displaystyle{{}##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \hfil
    \tabskip\alignsep@
}

This greatly simplifies the definition of \align@, by placing a big chunk of code in a macro. It also allows for changing the behavior of align by modifying \align@preamble (see Is it possible to make odd-numbered columns have implicitly a prefix {}?).

The LaTeX kernel uses a different method for tabular, because it needs to build the preamble according to its rules, that is, a combination of lcrp characters and so on.

The second usage for \span is for merging columns in an \halign. In Plain TeX we find \multispan

\def\multispan#1{\omit \mscount#1\relax
  \loop\ifnum\mscount>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\mscount\m@ne}

that does \omit and adds as many \span\omit pairs as stated in the argument (minus one); so \multispan{1} is equivalent to \omit, \multispan{2} to \omit\span\omit and so on. The \multicolumn macro of LaTeX is built upon the same idea

% latex.ltx, line 5053:
\long\def\multicolumn#1#2#3{\multispan{#1}\begingroup
  \@mkpream{#2}%
  \def\@sharp{#3}\set@typeset@protect
  \let\@startpbox\@@startpbox\let\@endpbox\@@endpbox
  \@arstrut \@preamble\hbox{}\endgroup\ignorespaces}

It first does \multispan{#1} (defined exactly as in Plain) and then proceeds to build a “local” alignment preamble using the same \@mkpream used by tabular and array to evaluate their mandatory argument.

Why did Knuth use the same primitive for two very different meanings? In order to save space; TeX was written when computer memory space was low, and saving on a definition was important. Since \span can only appear in \halign (or \valign, of course), it's not a problem.

A devious usage of \span in the first meaning appears in the solution of exercise 20.16 in the TeXbook

The following shouldn't be taken too seriously, but it does work:

{\setbox0=\vbox{\halign{#{\c\span\d}\cr
       \let\next=0\edef\next#1{\gdef\next{\b#1}}\next\cr}}}
 \let\a=\next

The exercise is about defining \a to be equivalent to \b (fully expanded) followed by \c (not expanded) and by \d (expanded just once) without using \noexpand and \the. For instance, if we have

\def\foo{xy\baz}
\def\baz{z}
\def\b{\foo\foo}
\def\c{--}
\def\d{\baz}

we want to define \a to have as its replacement text

xyzxyz\c\baz

The \setbox0=\vbox{ part is just to use \halign without any output. Now TeX evaluates the \halign preamble as #{\c\baz}\cr, because \span causes a one level expansion of \d. The only cell contains

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next

that, according to the rules, is used in place of # in the preamble, so that the input stream becomes

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next{\c\baz}\cr

The \cr just ends the cell, so it's not relevant. Because of \let\next=0, \next becomes unexpandable, so \edef causes \next to be defined as if it had been

\def\next#1{\gdef\next{<full expansion of \b>#1}}

and so \next{\c\baz} will dutifully execute

\gdef\next{<full expansion of \b>\c\baz}

and the final \let\a=\next ends it all.

This explains well that \span does only one step of expansion.


A different solution with e-TeX (it doesn't use \noexpand and \the, after all), would be

\edef\a{\b\unexpanded\expandafter{\expandafter\c\d}}
  • What is exactly happening in the solution of exercise 20.16? It would be nice to have an explanation. – Manuel Sep 27 '14 at 12:59
  • @Manuel I was writing it. – egreg Sep 27 '14 at 13:02
  • Great answer. Just one thing: I think you are missing a closed brace in \def\next#1{\gdef\next{<full expansion of \b>#1}, which should be \def\next#1{\gdef\next{<full expansion of \b>#1}}. First closed brace for \next's argument, second one ends definition. – MickG Sep 27 '14 at 13:47
  • Having no idea what \halign was, I googled and found this. Linking it here in case others may need it. And you're welcome. Thank you in fact. – MickG Sep 27 '14 at 14:34
  • And here is \valign. – MickG Sep 27 '14 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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