+\section{Output sequencing} \label{sec:output.sequencer}
+
+C compilers are picky about the order in which things are presented to them
+in their input; but information about the structure of our classes is
+scattered among a variety of different layout objects. It's not the case
+that a layout object only contributes to a single localized portion of the
+output: for example, a @|vtmsgs| layout object is responsible for declaring
+both the appropriate @|struct $C$__vtmsgs_$a$| structure in the header file,
+populated with method entry pointers, but also declaring its member in the
+enclosing @|struct $C$__vt_$i$| structure.
+
+One approach would be to have the various layout objects just know how to
+call each other in the right order so as to have everything come out
+properly. That would make extending the translator, e.g., to add new kinds
+of layout objects, rather difficult. And it doesn't let users insert custom
+C fragments in flexible ways.
+
+Instead, there's a clear separation between which things need to be output,
+and the order in which they're produced.
+
+Ordering is handled by a \emph{sequencer} object. A sequencer doesn't know
+anything particular about output: its job is simply to do things in a
+particular order. It's described here because Sod only uses it for output
+scheduling.
+
+A sequencer maintains a collection of named \emph{items}, each of which has a
+name and a list of functions associated with it. A name can be any Lisp
+object. Names are compared using @|equal|, so lists can be used to construct
+a hierarchical namespace.
+
+The sequencer also maintains a collection of \emph{constraints}, which take
+the form of lists of item names. A constraint of the form @|($N_1$, $N_2$,
+$\ldots$, $N_k$)| requires that the item named $N_1$ must be scheduled before
+the item named $N_2$, and so on, all of which must be scheduled before the
+item named $N_k$. Items with these names do not need to exist or be known to
+the sequencer. An item name may appear in any number of constraints, all of
+which apply.
+
+It might be that a collection of constraints is impossible to satisfy: for
+example, the set
+\begin{center} \codeface
+ (alice bob) \qquad (bob carol) \qquad (carol alice)
+\end{center}
+can't be satisfied, since the first constraint requires that @|alice|
+precedes @|bob|, but the third says that @|alice| must come after @|carol|,
+and the second that @|carol| comes after @|bob|: it's not possible that
+@|alice| comes before @|bob| and after @|bob|. In this case, the sequencer
+fails and signals an error of type @|inconsistent-merge-error|.
+
+It is possible, but tedious, to explicitly order an entire collection of
+items by adding constraints. In the absence of explicit constraints to order
+them, items are ordered according to the order in which constraints naming
+them were first added to the sequencer. Items not named in any constraint
+are not processed at all.
+
+For example, suppose we have the following constraints.
+\begin{center} \codeface
+ (perl java) \qquad
+ (lisp java) \qquad
+ (python icon) \qquad
+ (icon perl)
+\end{center}
+The constraints give us that $@|python| < @|icon| < @|perl| < @|java|$, and
+also $@|lisp| < @|java|$. In this case, @|lisp| precedes @|python| because
+@|lisp| is mentioned in the second constraint while @|python| isn't mentioned
+until the third. So the final processing order is
+\begin{center}
+ @|lisp|, \quad
+ @|python|, \quad
+ @|icon|, \quad
+ @|perl|, \quad
+ @|java|
+\end{center}
+