X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/27ec3825bd945bcdae0dca8ab2b4475c4722b313..e895be217c3be6769708da17c9ae87cb22db040e:/doc/structures.tex

diff --git a/doc/structures.tex b/doc/structures.tex
index c31503e..01e1ecd 100644
--- a/doc/structures.tex
+++ b/doc/structures.tex
@@ -30,8 +30,14 @@ classes and associated metadata.  Note that Sod's object system is very
 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.
 
@@ -45,9 +51,9 @@ structure.
 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}
-    {struct sod_instance \{ \\ \ind
-       const struct sod_vtable *_vt; \- \\
+\begin{describe}{ty}[struct sod_instance]
+    {struct sod_instance \{                                     \\ \ind
+       const struct sod_vtable *_vt;                          \-\\
      \};}
 
   The basic structure of all instances.  Members are as follows.
@@ -57,10 +63,10 @@ instances have the basic structure of a @|struct sod_instance|.
   \end{description}
 \end{describe}
 
-\begin{describe}[struct sod_vtable]{type}
-    {struct sod_vtable \{ \\ \ind
-       const SodClass *_class; \\
-       size_t _base; \- \\
+\begin{describe}{ty}[struct sod_vtable]
+    {struct sod_vtable \{                                       \\ \ind
+       const SodClass *_class;                                  \\
+       size_t _base;                                          \-\\
      \};}
 
   A vtable contains static metadata needed for efficient conversions and
@@ -87,40 +93,48 @@ metaclass, and @|SodClass| is a subclass of @|SodObject|.  Extensions can
 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}
 
 \begin{figure}[tbp]
   \begin{tabular}{p{10pt}p{10pt}}
     \begin{nprog}
-      struct SodObject__ilayout \{ \\ \ind
-        union \{ \\ \ind
-          struct SodObject__ichain_obj \{ \\ \ind
-            const struct SodObject__vt_obj *_vt; \- \\
-          \} obj; \- \\
-        \} obj; \- \\
+      struct SodObject__ilayout \{                              \\ \ind
+        union \{                                                \\ \ind
+          struct SodObject__ichain_obj \{                       \\ \ind
+            const struct SodObject__vt_obj *_vt;              \-\\
+          \} obj;                                             \-\\
+        \} obj;                                               \-\\
       \};
     \end{nprog}
     &
     \begin{nprog}
-      struct SodObject__vt_obj \{ \\ \ind
-        const SodClass *_class; \\
-        size_t _base; \\
-        struct SodObject__vtmsgs_obj \{ \\ \ind
-          void (*init)(SodObject *me, ...); \\
-          void (*init__v)(SodObject *me, va_list); \- \\
-        \} obj; \- \\
+      struct SodObject__vt_obj \{                               \\ \ind
+        const SodClass *_class;                                 \\
+        size_t _base;                                           \\
+        struct SodObject__vtmsgs_obj \{                         \\ \ind
+          void (*init)(SodObject *me, ...);                     \\
+          void (*init__v)(SodObject *me, va_list);              \\
+          int (*teardown)(SodObject *me);                     \-\\
+        \} obj;                                               \-\\
       \};
-    \end{nprog} \\
+    \end{nprog}                                                 \\
   \end{tabular}
   \caption{Instance and vtable layout of @|SodObject|}
   \label{fig:structures.root.sodobject}
 \end{figure}
 
-\begin{describe}[SodObject]{cls}
-    {[nick = obj, metaclass = SodClass, lisp_metaclass = sod_class] \\
-     class SodObject \{ \\ \ind
-       void init(?);
+\begin{describe}{cls}[SodObject]
+    {[nick = obj, metaclass = SodClass,
+      lisp_metaclass = sod_class]                               \\
+     class SodObject \{                                         \\ \ind
+       void init(?);                                          \-\\
      \}}
 
   The @|SodObject| class defines no slots.  Because @|SodObject| has no
@@ -135,9 +149,9 @@ recommended.
   The instance and vtable layout of @|SodObject| is shown in
   \xref{fig:structures.root.sodobject}.
 
-  The following message is defined.
+  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
@@ -147,15 +161,16 @@ recommended.
     method calls on its @|next_method| function more than once.
 
     This default behaviour is to initialize the instance's slots using the
-    defined slot initializers: each slot is initialized using the most
-    specific applicable initializer, if any.  Slots without an initializer
-    are left uninitialized.
+    defined slot initializers, and execute the initialization fragments.
+    Each slot is initialized using the most specific applicable initializer,
+    if any.  Slots without an initializer are left uninitialized.
 
-    Slots are initialized in reverse-precedence order of their defining
-    classes; i.e., slots defined by a less specific superclass are
-    initialized earlier than slots defined by a more specific superclass.
-    Slots defined by the same class are initialized in the order in which
-    they appear in the class definition.
+    Slots are initialized and initialization fragments executed together, a
+    superclass at a time: first, the superclass's slots are initialized (if
+    any); then the superclass's initialization fragments (if any) are
+    executed, starting with the least specific superclass first.  Slots and
+    initialization fragments defined by the same class are processed in the
+    order in which they appear in the class definition.
 
     There are no standard keyword arguments; methods on subclasses are free
     to introduce their own in the usual way.
@@ -167,29 +182,54 @@ recommended.
     For more details on instance construction, see
     \xref{sec:concepts.lifecycle.birth}.
   \end{describe}
+
+  \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
+    instance is safe to deallocate.  A nonzero value means that the instance
+    should not be deallocated, and that it is safe for the caller to simply
+    forget about it.  This simple protocol may be used, for example, to
+    implement a reference-counting system.
+
+    This message uses a custom method combination which works like the
+    standard method combination except that default behaviour is invoked if
+    no primary or around method overrides.
+
+    This default behaviour is to execute each superclass's teardown
+    fragments, most specific first, and then return zero to indicate that the
+    object is ready for deallocation.  Teardown fragments defined by the same
+    class are processed in the order in which they appear in the class
+    definition.
+
+    It is usual to provide complex teardown behaviour as @|before| methods.
+    Logic to decide whether to allow deallocation is usually implemented as
+    @|around| methods.
+  \end{describe}
 \end{describe}
 
 
 \subsection{The SodClass class} \label{sec:structures.root.sodclass}
 
-\begin{describe}[SodClass]{cls}
-    {[nick = cls, link = SodObject] \\
-     class SodClass : SodObject \{ \\ \ind
-       const char *name; \\
-       const char *nick; \\
-       size_t initsz; \\
-       void *(*imprint)(void *@<p>); \\
-       size_t n_supers; \\
-       const SodClass *const *supers; \\
-       size_t n_cpl; \\
-       const SodClass *const *cpl; \\
-       const SodClass *link; \\
-       const SodClass *head; \\
-       size_t level; \\
-       size_t n_chains; \\
-       const struct sod_chain *chains; \\
-       size_t off_islots; \\
-       size_t islotsz; \- \\
+\begin{describe}{cls}[SodClass]
+    {[nick = cls, link = SodObject]                             \\
+     class SodClass: SodObject \{                               \\ \ind
+       const char *name;                                        \\
+       const char *nick;                                        \\
+       size_t initsz;                                           \\
+       size_t align;                                            \\
+       void *(*imprint)(void *@<p>);                            \\
+       size_t n_supers;                                         \\
+       const SodClass *const *supers;                           \\
+       size_t n_cpl;                                            \\
+       const SodClass *const *cpl;                              \\
+       const SodClass *link;                                    \\
+       const SodClass *head;                                    \\
+       size_t level;                                            \\
+       size_t n_chains;                                         \\
+       const struct sod_chain *chains;                          \\
+       size_t off_islots;                                       \\
+       size_t islotsz;                                        \-\\
      \}}
 
   The @|SodClass| class defines no additional messages , but there are a
@@ -205,6 +245,8 @@ recommended.
 
   \item[initsz] The size in bytes required to store an instance of the class.
 
+  \item[align] A sufficient alignment for the class's instance storage.
+
   \item[imprint] A pointer to a function: given a pointer @<p> to at least
     @<initsz> bytes of appropriately aligned memory, `imprint' this memory it
     so that it becomes a minimally functional instance of the class: all of
@@ -259,13 +301,13 @@ recommended.
   \end{description}
 \end{describe}
 
-\begin{describe}[struct sod_chain]{type}
-    {struct sod_chain \{ \\ \ind
-       size_t n_classes; \\
-       const SodClass *const *classes; \\
-       size_t off_ichain; \\
-       const struct sod_vtable *vt; \\
-       size_t ichainsz; \- \\
+\begin{describe}{ty}[struct sod_chain]
+    {struct sod_chain \{                                        \\ \ind
+       size_t n_classes;                                        \\
+       const SodClass *const *classes;                          \\
+       size_t off_ichain;                                       \\
+       const struct sod_vtable *vt;                             \\
+       size_t ichainsz;                                       \-\\
      \};}
 
   The @|struct sod_chain| structure describes an individual chain of
@@ -321,25 +363,25 @@ The entire state of an instance of $C$ is contained in a single structure of
 type @|struct $C$__ilayout|.
 
 \begin{prog}
-  struct $C$__ilayout \{ \\ \ind
-    union $C$__ichainu_$h$ \{ \\ \ind
-      struct $C$__ichain_$h$ \{ \\ \ind
-        const struct $C$__vt_$h$ *_vt; \\
-        struct $H$__islots $h$; \\
-        \quad$\vdots$ \\
-        struct $C$__islots \{ \\ \ind
-          @<type>_1 @<slot>_1; \\
-          \quad$\vdots$ \\
-          @<type>_n @<slot>_n; \- \\
-        \} $c$; \- \\
-      \} $c$; \\
-      struct $H$__ichain_$h$ $h$; \\
-      \quad$\vdots$ \- \\
-    \} $h$; \\
-    union $B$__ichainu_$i$ $i$; \\
-    \quad$\vdots$ \- \\
-  \};
-  \\+
+  struct $C$__ilayout \{                                        \\ \ind
+    union $C$__ichainu_$h$ \{                                   \\ \ind
+      struct $C$__ichain_$h$ \{                                 \\ \ind
+        const struct $C$__vt_$h$ *_vt;                          \\
+        struct $H$__islots $h$;                                 \\
+        \quad$\vdots$                                           \\
+        struct $C$__islots \{                                   \\ \ind
+          @<type>_1 @<slot>_1;                                  \\
+          \quad$\vdots$                                         \\
+          @<type>_n @<slot>_n;                                \-\\
+        \} $c$;                                               \-\\
+      \} $c$;                                                   \\
+      struct $A$__ichain_$h$ $a$;                               \\
+      \quad$\vdots$                                           \-\\
+    \} $h$;                                                     \\
+    union $B$__ichainu_$i$ $i$;                                 \\
+    \quad$\vdots$                                             \-\\
+  \};                                                           \\+
+
   typedef struct $C$__ichain_$h$ $C$;
 \end{prog}
 
@@ -350,7 +392,7 @@ transitive closure of the `links to' relation.)  Chains are identified by
 naming their least specific classes; the least specific class in a chain is
 called the \emph{chain head}.  Suppose that the chain head of the chain
 containing $C$ itself is named $H$ (though keep in mind that it's possible
-that .$H$ is in fact $C$ itself.)
+that $H$ is in fact $C$ itself.)
 
 \subsubsection{The ilayout structure}
 The @|ilayout| structure contains one member for each of $C$'s superclass
@@ -379,12 +421,11 @@ and this is followed by corresponding members
   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}
@@ -415,39 +456,41 @@ vtable pointer
 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.
 \begin{prog}
-  union $C$__vtu_$h$ \{ \\ \ind
-    struct $C$__vt_$h$ \{ \\ \ind
-      const $P$ *_class; \\
-      size_t _base; \\
-      \quad$\vdots$ \\
-      const $Q$ *_cls_$j$; \\
-      \quad$\vdots$ \\
-      ptrdiff_t _off_$i$; \\
-      \quad$\vdots$ \\
-      struct $C$__vtmsgs_$a$ \{ \\ \ind
-        @<type> (*@<msg>)($C$ *, $\dots$); \\
-        \quad$\vdots$ \- \\
-      \} $a$; \\
-      \quad$\vdots$ \- \\
-    \} $c$; \- \\
-  \};
-  \\+
+  union $C$__vtu_$h$ \{                                         \\ \ind
+    struct $C$__vt_$h$ \{                                       \\ \ind
+      const $P$ *_class;                                        \\
+      size_t _base;                                             \\
+      \quad$\vdots$                                             \\
+      const $Q$ *_cls_$j$;                                      \\
+      \quad$\vdots$                                             \\
+      ptrdiff_t _off_$i$;                                       \\
+      \quad$\vdots$                                             \\
+      struct $C$__vtmsgs_$a$ \{                                 \\ \ind
+        @<type> (*@<msg>)($C$ *, $\dots$);                      \\
+        \quad$\vdots$                                         \-\\
+      \} $a$;                                                   \\
+      \quad$\vdots$                                           \-\\
+    \} $c$;                                                   \-\\
+  \};                                                           \\+
+
   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}
@@ -456,18 +499,11 @@ The outer layer is a @|union $C$__vtu_$h$| containing a member
 for each of $C$'s superclasses $A$ in the same chain, with $C$ itself listed
 first.
 
-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
+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
 \begin{prog}
   const union $A$__vtu_$i$ $C$__vtable_$i$;
 \end{prog}
@@ -506,14 +542,14 @@ traversal.
 
 \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.
@@ -560,9 +596,12 @@ defined as
 \end{prog}
 or a standard message which takes keyword arguments, defined as
 \begin{prog}
-  @<type>_0 $m$(\=@<type>_1 @<arg>_1, $\ldots$, @<type>_n @<arg>_n? \+ \\
-                  @<type>_{n+1} @<kw>_{n+1} @[= @<dflt>_{n+1}@], $\ldots$,
-                  @<type>_m @<kw>_m @[= @<dflt>_m@]);
+  @<type>_0 $m$(\=@<type>_1 @<arg>_1,
+                    $\ldots$,
+                    @<type>_n @<arg>_n?                       \+\\
+                  @<type>_{n+1} @<kw>_{n+1} @[= @<dflt>_{n+1}@],
+                    $\ldots$,
+                    @<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
@@ -570,7 +609,7 @@ argument of type @|va_list| in place of the variable portion of the argument
 list or keywords.
 \begin{prog}
   @<type>_0 $m$($C$ *me, @<type>_1 @<arg>_1, $\ldots$,
-                @<type>_n @<arg>_n, \dots); \\
+                @<type>_n @<arg>_n, \dots);                     \\
   @<type>_0 $m$__v($C$ *me, @<type>_1 @<arg>_1, $\ldots$,
                    @<type>_n @<arg>_n, va_list sod__ap);
 \end{prog}
@@ -609,14 +648,23 @@ defined for the sake of completeness.
 
 Finally, the class object is defined as
 \begin{prog}
-  extern const struct $R$__ilayout $C$__classobj; \\
-  \#define $C$__class (\&$C$__classobj.$j$.$r$)
+  extern const struct $R$__ilayout $C$__classobj;               \\
+  \#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 --------------------------------------------------
 
