13

I am currently looking somewhat carefully at how TeX manipulates skips, and I am having trouble finding practical use cases for skips with a negative stretch or shrink component, such as \Askip and \Bskip in the following.

\newskip\Askip
\newskip\Bskip
\Askip 0pt plus -2pt minus 3pt
\Bskip 0pt plus 1fil minus -4bp

They lead to odd situations. For instance, putting a skip with a large negative stretch component in a box that it somewhat underfull will cause other skips to shrink proportionally to their stretch component.

\hbox to 200pt{A B C\hskip 0pt plus -50pt}\bye

What happens is that since the box is underfull, TeX looks at the sum of the available stretch components. Since this sum is negative, the stretch components are multipled by a negative number.

So, obviously this example is not useful, but are there some more useful examples of what negative glue can be used for?

  • 5
    I'd say that negative shrink components might be useful for compensating positive ones. See \hfilneg and \vfilneg (where the shrink component is infinite). – egreg Mar 6 '12 at 13:56
  • +1 to a young BLF :) – user4686 Jan 12 at 21:06
4

In short, negative stretch and shrink can be combined with positive ones to “cancel out”, as mentioned by @egreg and @David. This makes it possible for the line-breaking algorithm to automatically make some complex choices.

That's really the full answer, but just to elaborate: There are some examples in The TeXbook, but such things are explained and organized better in the paper Breaking Paragraphs into Lines by Knuth and Plass (you can find it online; also reprinted in Digital Typography with some minor corrections).

The first example given in the paper is:

Although the box/glue/penalty model appears at first glance to be oriented solely to the problem of justified text, we shall now see that it is powerful enough to be adapted to the analogous problem of unjustified typesetting: [...] The idea is to let spaces between words be represented by the sequence

glue(0,18,0)
penalty(0,0,0)
glue(6,-18,0)

instead of the ‘glue(6,3,2)’ we used for justified typesetting. [...] If a break occurs at the penalty, there will be a stretchability of 18 units on the line, and the ‘glue(6,-18,0)’ will be discarded after the break so that the next line will begin flush left. On the other hand if no break occurs, the net effect is to have glue(6,0,0), representing a normal space with no stretching or shrinking.

Note that the stretchability of -18 in the second glue item has no physical significance, but it nicely cancels out the stretchability of +18 in the first glue item. Negative stretchability has several interesting applications, so the reader should study this example carefully before proceeding to the more elaborate constructions below.

To reproduce the above (sort of) with TeX syntax, compile the following with pdftex:

\def\randomword{\ifcase\pdfuniformdeviate6 one\or two\or three\or four\or five\or six\fi}
\def\oneword{\randomword\hskip 0pt plus 18pt\penalty 0\hskip 3.333pt plus -18pt\relax}
\def\tenwords{\oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword}
\def\paragraph{\tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords}

\hsize=4.5in 

\paragraph

\bye

to get something like:

paragraph

(This is not how \raggedright is implemented in TeX—that uses \rightskip—but this one adds stretchability on each line instead of constant space between words.)

As the paper goes on to show, the same idea can be used for inserting optional hyphens in ragged-right paragraphs, and for “ragged-centered” paragraphs:

\def\randomword{\ifcase\pdfuniformdeviate6 one\or two\or three\or four\or five\else six\fi}
\def\oneword{%
  \randomword
  \hskip 0pt plus 18pt
  \penalty 0
  \hskip 3.333pt plus -36pt\relax
  \hbox{}
  \penalty 10000
  \hskip 0pt plus 18pt
}
\def\tenwords{\oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword}
\def\paragraph{%
  \noindent
  \hskip 0pt plus 18pt
  \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \randomword
  \hskip 0pt plus 18pt
  \penalty -10000
}
\hsize=4.5in 
\paragraph
\bye

— the idea is that if the break at the \penalty 0 is taken, then the line being broken ends with a glue of \hskip 0pt plus 18pt and the next one starts with \hbox{}\penalty 10000\hskip 0pt plus 18pt (so basically, that amount of stretch), while if the break is not taken, then all the glues cancel out.

Then this idea is used for typesetting computer programs at different widths simply by changing \hsize and nothing else:

Pascal programs

(Knuth wrote a preprocessor to generate the TeX files for these PASCAL programs; it was called BLAISE.)

Finally,

The final application of line breaking that we shall study is the most difficult one that has so far been encountered by the authors; it was solved only after acquiring more than two years of experience with more straightforward line-breaking tasks, since the full power of the box/glue/penalty primitives was not immediately apparent.

And this is to typeset a certain index and get any of the following simply by varying \hsize:

MR index

The features here in each entry are:

  • There's a name (possibly too long to fit on a line), followed by dot leaders, followed by a list of review numbers (possibly too long to fit on a line).

  • All lines after the first should be indented (hanging indentation).

  • The name part, if broken, should be left-aligned (ragged-right); the numbers part, if broken, should be right-aligned (ragged-left) with indentation.

  • If the dot leaders end a line, they should stop at a certain distance before the end of line; also the ragged-right lines should have a max width a certain (other) distance before the end of line.

  • Minimize whitespace, and (secondarily) minimize the number of lines for the numbers.

There's a way to achieve all this while keeping the input simply something like:

ACM Symposium on Theory of Computing, Eighth Annual (Hershey, %
Pa., 1976)\:1879, 4813, 5414, 6918, 6936, 6937, 6946, 6951, %
6970, 7619, 9605, 10148, 11676, 11687, 11692, 11710, 13869

and negative stretch and shrink are involved in the solution: see the paper, or see the section “7. Paragraph maneuvers” in Appendix D: Dirty Tricks of the TeXbook, page 392–394. The paper goes on to give an “algebra” that can help one come up with the right tricks for such tasks.

The same idea also applies to page-breaking; see \beginsection in plain.tex, or \vfilneg, or the package needspace.

12

As @egreg mentioned in comments, they are usually paired with equal positive values.

plain and latex both have

 \def\filbreak{\par\vfil\penalty-200\vfilneg}

if the break happens the negative stretch is thrown away at the top of the next page, but if it does not happen, it counteracts the fil space before the penalty leaving zero total stretch.

  • package needspace also illustrates this. – user4686 Jan 12 at 21:05
3

maybe not exactly what is requested, but an absolute negative skip is useful in creating composite symbols, e.g.

x \rightarrow\mskip-15mu\rightarrow\mskip-15mu\rightarrow y

will give you

a three-headed arrow

it's also instructive to notice that \llap, \rlap, \clap and their vertical friends are all based on \hss or \vss which are primitives defined with infinite (positive) shrink and stretch. \llap is immensely useful for positioning page numbers flush right in a table of contents. and marginal notes couldn't exist without these facilities.

  • I could see how absolute negative skips are useful (although here you could equally well use \mkern, I believe). Thanks for mentionning \llap and friends. – Bruno Le Floch Mar 6 '12 at 19:42
  • yes, you could definitely use \mkern and i probably should have. still, it's the negative value that's most relevant to your question. there are some good examples in the texbook if you follow the index entries for hss. – barbara beeton Mar 6 '12 at 21:55
  • Actually, \hss and \vss do not have negative stretch and shrink. They are equivalent to skips by 0pt plus 1fil minus 1fil. – Bruno Le Floch Jul 11 '14 at 23:00

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.