flexible and it's possible for an extension to define a new root class which
works very differently from the standard @|SodObject| described here.
-The concrete types described in \xref{sec:structures.common} and
-\ref{sec:structures.root} are declared by the header file @|<sod/sod.h>|.
+The concrete types described in
+\xref[\instead{sections}]{sec:structures.common} and
+\ref{sec:structures.root} are declared by the header file
+@|<sod/sod.h>|.\footnote{%
+ This isn't completely true. The @|SodObject| and @|SodClass| structures
+ are defined in a header called @|<sod/sod-base.h>|, which is generated by
+ the Sod translator; but @|<sod/sod.h>| includes @|<sod/sod-base.h>|, so you
+ can forget about this detail.} %
The definitions described in \xref{sec:structures.layout} are defined in the
header file generated by the containing module.
Instance chains contain slots and vtable pointers, as described below. All
instances have the basic structure of a @|struct sod_instance|.
-\begin{describe}[struct sod_instance]{type}
+\begin{describe}{ty}[struct sod_instance]
{struct sod_instance \{ \\ \ind
const struct sod_vtable *_vt; \-\\
\};}
\end{description}
\end{describe}
-\begin{describe}[struct sod_vtable]{type}
+\begin{describe}{ty}[struct sod_vtable]
{struct sod_vtable \{ \\ \ind
const SodClass *_class; \\
size_t _base; \-\\
define additional root classes, but this is tricky, and not really to be
recommended.
+The class definitions shown in the synopses are intended to be informative,
+but are fictional and can't really work: these classes are really defined by
+Lisp code in the Sod translator, in order to deal with the circularities
+involved at the top of the class/metaclass graph (see
+\xref{sec:concepts.metaclasses.runtime}).
+
\subsection{The SodObject class} \label{sec:structures.root.sodobject}
\label{fig:structures.root.sodobject}
\end{figure}
-\begin{describe}[SodObject]{cls}
+\begin{describe}{cls}[SodObject]
{[nick = obj, metaclass = SodClass,
lisp_metaclass = sod_class] \\
class SodObject \{ \\ \ind
- void init(?);
+ void init(?); \-\\
\}}
The @|SodObject| class defines no slots. Because @|SodObject| has no
The following messages are defined.
- \begin{describe}[obj.init]{msg}{void init(?);}
+ \begin{describe}{msg}[obj.init]{void init(?);}
Initialize a newly allocated instance.
This message uses a custom method combination which works like the
\xref{sec:concepts.lifecycle.birth}.
\end{describe}
- \begin{describe}[obj.teardown]{msg}{int teardown();}
+ \begin{describe}{msg}[obj.teardown]{int teardown();}
Teardown an instance which is no longer required.
The message returns an integer flag. A zero value means that the
\subsection{The SodClass class} \label{sec:structures.root.sodclass}
-\begin{describe}[SodClass]{cls}
+\begin{describe}{cls}[SodClass]
{[nick = cls, link = SodObject] \\
- class SodClass : SodObject \{ \\ \ind
+ class SodClass: SodObject \{ \\ \ind
const char *name; \\
const char *nick; \\
size_t initsz; \\
\end{description}
\end{describe}
-\begin{describe}[struct sod_chain]{type}
+\begin{describe}{ty}[struct sod_chain]
{struct sod_chain \{ \\ \ind
size_t n_classes; \\
const SodClass *const *classes; \\
@<type>_n @<slot>_n; \-\\
\} $c$; \-\\
\} $c$; \\
- struct $H$__ichain_$h$ $h$; \\
+ struct $A$__ichain_$h$ $a$; \\
\quad$\vdots$ \-\\
\} $h$; \\
union $B$__ichainu_$i$ $i$; \\
struct $A$__ichain_$h$ $a$;
\end{prog}
for each of $C$'s superclasses $A$ in the same chain in some (unimportant)
-order.
+order. The (somewhat obtuse) purpose of this union is to engage the `common
+initial sequence' rule of \cite[6.5.2.3]{iso-1990:c,ansi-1999:c}.
\subsubsection{The ichain structure}
-The
-@|ichain|
-structure contains (in order), a pointer
+The @|ichain| structure contains (in order), a pointer
\begin{prog}
const struct $C$__vt_$h$ *_vt;
\end{prog}
In general, the vtables for the different chains will have \emph{different}
structures.
-The instance layout split neatly into disjoint chains. This is necessary
+The instance layout splits neatly into disjoint chains. This is necessary
because each @|ichain| must have as a prefix the @|ichain| for each
superclass in the same chain, and each slot must be stored in exactly one
place. The layout of vtables doesn't have this second requirement: it
doesn't matter that there are multiple method entry pointers for the same
effective method as long as they all work correctly. Indeed, it's essential
-that they do, because each chain's method entry function will need to apply a
-different offset to the receiver pointer before invoking the effective
-method.
+that there are multiple entry pointers, because each chain's method entry
+function will need to apply a different offset to the receiver pointer before
+invoking the effective method.
A vtable for a class $C$ with chain head $H$ has the following general
structure.
extern const union $C$__vtu_$h$ $C$__vtable_$h$;
\end{prog}
+In the following, let $M$ be the metaclass of $C$.
+
\subsubsection{The vtu union}
The outer layer is a @|union $C$__vtu_$h$| containing a member
\begin{prog}
This is mostly an irrelevant detail, whose purpose is to defend against
malicious compilers: pointers are always to one of the inner @|vt|
-structures. It's important only because it's the outer @|vtu| union which is
-exported by name. Specifically, for each chain of $C$'s superclasses there is
-an external object
+structures. It's important only because it's the outer @|vtu| union which is
+exported by name. Specifically, for each chain of $C$'s superclasses there
+is an external object
\begin{prog}
const union $A$__vtu_$i$ $C$__vtable_$i$;
\end{prog}
\item Let $N$ be the metaclass of $A$. Examine the superclass chains of $N$
in order of decreasing specificity of their most-specific classes. Let $J$
- be the chain head of such a chain, and let $Q$ be the most specific
- superclass of $M$ in the same chain as $J$. Then, if there is currently no
- class pointer of type $Q$, then add a member
+ be the chain head of such a chain. If there is currently no class pointer
+ for the chain headed by $J$, then add a member
\begin{prog}
const $Q$ *_cls_$j$;
\end{prog}
to the vtable pointing to the appropriate @|islots| structure within $M$'s
- class object.
+ class object, where $Q$ is the most specific superclass of $M$ in the same
+ chain as $J$.
\item Examine the superclass chains of $A$ in order of decreasing specificity
of their most-specific classes. Let $I$ be the chain head of such a chain.
@<type>_n @<arg>_n? \+\\
@<type>_{n+1} @<kw>_{n+1} @[= @<dflt>_{n+1}@],
$\ldots$,
- @<type>_m @<kw>_m @[= @<dflt>_m@]);
+ @<type>_{n'} @<kw>_{n'} @[= @<dflt>_{n'}@]);
\end{prog}
two entry points are defined: the usual `main' entry point which accepts a
variable number of arguments, and a `valist' entry point which accepts an
Finally, the class object is defined as
\begin{prog}
extern const struct $R$__ilayout $C$__classobj; \\
- \#define $C$__class (\&$C$__classobj.$j$.$r$)
+ \#define $C$__class (\&$C$__classobj.$j$.$r$) \\
+ \#define $C$__cls_$k$ (\&$C$__classobj.$k$.$n$) \\
+ \quad$\vdots$
\end{prog}
The exported symbol @|$C$__classobj| contains the entire class instance.
This is usually rather unwieldy. The macro @|$C$__class| is usable as a
pointer of type @|const $R$~*|, where $R$ is the root metaclass of $C$, i.e.,
the metaclass of the least specific superclass of $C$; usually this is
-@|const SodClass~*|.
+@|const SodClass~*|. For each chain of $C$'s metaclass, a macro
+@|$C$__cls_$k$| is defined, usable as a pointer of type @|const $N$~*|, where
+$K$ and $N$ are the chain's head and tail classes (i.e., the least- and
+most-specific classes in the chain) respectively; this macro is
+\emph{omitted} if $N = R$, i.e., in the common case where $C$'s metaclass is
+precisely the root metaclass, since the existing @|$C$__class| macro is
+already sufficient.
+
%%%----- That's all, folks --------------------------------------------------