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

diff --git a/doc/concepts.tex b/doc/concepts.tex
index f5e3a2f..b4e80ca 100644
--- a/doc/concepts.tex
+++ b/doc/concepts.tex
@@ -666,10 +666,13 @@ Construction of a new instance of a class involves three steps.
   necessary.
 \end{enumerate}
 The \descref{SOD_DECL}[macro]{mac} handles constructing instances with
-automatic storage duration (`on the stack').  Programmers can add support for
-other allocation strategies by using the \descref{SOD_INIT}[macro]{mac} and
-the \descref{sod_init}{fun} and \descref{sod_initv}{fun} functions, which
-package up imprinting and initialization.
+automatic storage duration (`on the stack').  Similarly, the
+\descref{SOD_MAKE}[macro]{mac} and the \descref{sod_make}{fun} and
+\descref{sod_makev}{fun} functions construct instances allocated from the
+standard @|malloc| heap.  Programmers can add support for other allocation
+strategies by using the \descref{SOD_INIT}[macro]{mac} and the
+\descref{sod_init}{fun} and \descref{sod_initv}{fun} functions, which package
+up imprinting and initialization.
 
 \subsubsection{Allocation}
 Instances of most classes (specifically including those classes defined by
@@ -701,7 +704,7 @@ the platform's strictest alignment requirement applies.
 The following simple function correctly allocates and returns space for an
 instance of a class given a pointer to its class object @<cls>.
 \begin{prog}
-  void *allocate_instance(const SodClass *cls) \\ \ind
+  void *allocate_instance(const SodClass *cls)                  \\ \ind
     \{ return malloc(cls@->cls.initsz); \}
 \end{prog}
 
@@ -725,7 +728,7 @@ of any use unless they've been written specifically for the purpose.
 The following simple function imprints storage at address @<p> as an instance
 of a class, given a pointer to its class object @<cls>.
 \begin{prog}
-  void imprint_instance(const SodClass *cls, void *p) \\ \ind
+  void imprint_instance(const SodClass *cls, void *p)           \\ \ind
     \{ cls@->cls.imprint(p); \}
 \end{prog}
 
@@ -742,10 +745,10 @@ Initialization is performed by sending the imprinted instance an @|init|
 message, defined by the @|SodObject| class.  This message uses a nonstandard
 method combination which works like the standard combination, except that the
 \emph{default behaviour}, if there is no overriding method, is to initialize
-the instance's slots using the initializers defined in the class and its
-superclasses.  This default behaviour may be invoked multiple times if some
-method calls on its @|next_method| more than once, unless some other method
-takes steps to prevent this.
+the instance's slots, as described below, and to invoke each superclass's
+initialization fragments.  This default behaviour may be invoked multiple
+times if some method calls on its @|next_method| more than once, unless some
+other method takes steps to prevent this.
 
 Slots are initialized in a well-defined order.
 \begin{itemize}
@@ -755,34 +758,65 @@ Slots are initialized in a well-defined order.
   their definitions appear.
 \end{itemize}
 
-The recommended way to add new initialization behaviour is to define @|after|
-methods on the @|init| message.  These will be run after the slot
-initializers have been applied, in reverse precedence order.
-
-Initialization is \emph{parametrized}, so the caller may select from a space
-of possible initial states for the new instance, or to inform the new
-instance about some other objects known to the caller.  Specifically, the
-@|init| message accepts keyword arguments (\xref{sec:concepts.keywords})
-which can be defined and used by methods defined on it.
-
-\subsubsection{Example}
-The following is a simple function, with syntactic-sugar macro, which
-allocate storage for an instance of a class, imprints and initializes it, and
-returns a pointer to the new instance.
-\begin{prog}
-  void *make_instance(const SodClass *c, @|\dots|) \\
-  \{ \\ \ind
-    va_list ap;
-    void *p = malloc(c@->cls.initsz); \\
-    if (!p) return (0); \\
-    va_start(ap, c); \\
-    sod_initv(c, p, ap); \\
-    va_end(ap); \\
-    return (p); \- \\
-  \}
-  \\+
-  \#define MAKE(cls, keys) (cls *)make_instance(cls\#\#__class, keys)
-\end{prog}
+A class can define \emph{initialization fragments}: pieces of literal code to
+be executed to set up a new instance.  Each superclass's initialization
+fragments are executed with @|me| bound to an instance pointer of the
+appropriate superclass type, immediately after that superclass's slots (if
+any) have been initialized; therefore, fragments defined by a more specific
+superclass are executed after fragments defined by a more specific
+superclass.  A class may define more than one initialization fragment: the
+fragments are executed in the order in which they appear in the class
+definition.  It is possible for an initialization fragment to use @|return|
+or @|goto| for special control-flow effects, but this is not likely to be a
+good idea.
+
+The @|init| message accepts keyword arguments
+(\xref{sec:concepts.methods.keywords}).  The set of acceptable keywords is
+determined by the applicable methods as usual, but also by the
+\emph{initargs} defined by the receiving instance's class and its
+superclasses, which are made available to slot initializers and
+initialization fragments.
+
+There are two kinds of initarg definitions.  \emph{User initargs} are defined
+by an explicit @|initarg| item appearing in a class definition: the item
+defines a name, type, and (optionally) a default value for the initarg.
+\emph{Slot initargs} are defined by attaching an @|initarg| property to a
+slot or slot initializer item: the property's determines the initarg's name,
+while the type is taken from the underlying slot type; slot initargs do not
+have default values.  Both kinds define a \emph{direct initarg} for the
+containing class.
+
+Initargs are inherited.  The \emph{applicable} direct initargs for an @|init|
+effective method are those defined by the receiving object's class, and all
+of its superclasses.  Applicable direct initargs with the same name are
+merged to form \emph{effective initargs}.  An error is reported if two
+applicable direct initargs have the same name but different types.  The
+default value of an effective initarg is taken from the most specific
+applicable direct initarg which specifies a defalt value; if no applicable
+direct initarg specifies a default value then the effective initarg has no
+default.
+
+All initarg values are made available at runtime to user code --
+initialization fragments and slot initializer expressions -- through local
+variables and a @|suppliedp| structure, as in a direct method
+(\xref{sec:concepts.methods.keywords}).  Furthermore, slot initarg
+definitions influence the initialization of slots.
+
+The process for deciding how to initialize a particular slot works as
+follows.
+\begin{enumerate}
+\item If there are any slot initargs defined on the slot, or any of its slot
+  initializers, \emph{and} the sender supplied a value for one or more of the
+  corresponding effective initargs, then the value of the most specific slot
+  initarg is stored in the slot.
+\item Otherwise, if there are any slot initializers defined which include an
+  initializer expression, then the initializer expression from the most
+  specific such slot initializer is evaluated and its value stored in the
+  slot.
+\item Otherwise, the slot is left uninitialized.
+\end{enumerate}
+Note that the default values (if any) of effective initargs do \emph{not}
+affect this procedure.
 
 
 \subsection{Destruction}
@@ -796,32 +830,61 @@ steps.
 \item \emph{Deallocation} releases the memory used to store the instance so
   that it can be reused.
 \end{enumerate}
+Teardown alone, for objects which require special deallocation, or for which
+deallocation occurs automatically (e.g., instances with automatic storage
+duration, or instances whose storage will be garbage-collected), is performed
+using the \descref{sod_teardown}[function]{fun}.  Destruction of instances
+allocated from the standard @|malloc| heap is done using the
+\descref{sod_destroy}[function]{fun}.
 
 \subsubsection{Teardown}
-Details of teardown are class-specific, but typically it involves releasing
-resources held by the instance, and possibly unlinking it from some larger
-data structure which used to keep track of it.
+Details of initialization are necessarily class-specific, but typically it
+involves setting the instance's slots to appropriate values, and possibly
+linking it into some larger data structure to keep track of it.
+
+Teardown is performed by sending the instance the @|teardown| message,
+defined by the @|SodObject| class.  The message returns an integer, used as a
+boolean flag.  If the message returns zero, then the instance's storage
+should be deallocated.  If the message returns nonzero, then it is safe for
+the caller to forget about instance, but should not deallocate its storage.
+This is \emph{not} an error return: if some teardown method fails then the
+program may be in an inconsistent state and should not continue.
 
-There is no provided protocol for teardown: classes whose instances require
-teardown behaviour must define and implement an appropriate protocol of their
-own.  The following class may serve for simple cases.
+This simple protocol can be used, for example, to implement a reference
+counting system, as follows.
 \begin{prog}
-  [nick = disposable] \\
-  class DisposableObject : SodObject \{ \\- \ind
-    void release() \{ ; \} \\
-    \quad /* Release resources held by the receiver. */ \- \\-
-  \}
-  \\+
-  code c : user \{ \\- \ind
-    /* If p is a a DisposableObject then release its resources. */ \\
-    void maybe_dispose(void *p) \\
-    \{ \\ \ind
-      DisposableObject *d = SOD_CONVERT(DisposableObject, p); \\
-      if (d) DisposableObject_release(d); \- \\
-    \} \- \\
+  [nick = ref]                                                  \\
+  class ReferenceCountedObject \{                               \\ \ind
+    unsigned nref = 1;                                          \\-
+    void inc() \{ me@->ref.nref++; \}                           \\-
+    [role = around]                                             \\
+    int obj.teardown()                                          \\
+    \{                                                          \\ \ind
+      if (--\,--me@->ref.nref) return (1);                      \\
+      else return (CALL_NEXT_METHOD);                         \-\\
+    \}                                                        \-\\
   \}
 \end{prog}
 
+This message uses a nonstandard method combination which works like the
+standard combination, except that the \emph{default behaviour}, if there is
+no overriding method, is to execute the superclass's teardown fragments, and
+to return zero.  This default behaviour may be invoked multiple times if some
+method calls on its @|next_method| more than once, unless some other method
+takes steps to prevent this.
+
+A class can define \emph{teardown fragments}: pieces of literal code to be
+executed to shut down an instance.  Each superclass's teardown fragments are
+executed with @|me| bound to an instance pointer of the appropriate
+superclass type; fragments defined by a more specific superclass are executed
+before fragments defined by a more specific superclass.  A class may define
+more than one teardown fragment: the fragments are executed in the order in
+which they appear in the class definition.  It is possible for an
+initialization fragment to use @|return| or @|goto| for special control-flow
+effects, but this is not likely to be a good idea.  Similarly, it's probably
+a better idea to use an @|around| method to influence the return value than
+to write an explicit @|return| statement in a teardown fragment.
+
 \subsubsection{Deallocation}
 The details of instance deallocation are obviously specific to the allocation
 strategy used by the instance, and this is often orthogonal from the object's
@@ -832,19 +895,6 @@ of the object's direct class.  Low-level details of deallocation often
 require the proper base address of the instance's storage, which can be
 determined using the \descref{SOD_INSTBASE}[macro]{mac}.
 
-\subsubsection{Example}
-The following is a counterpart to the @|new_instance| function
-(\xref{sec:concepts.lifecycle.birth}), which tears down and deallocates an
-instance allocated using @|malloc|.
-\begin{prog}
-  void free_instance(void *p) \\
-  \{ \\ \ind
-    SodObject *obj = p; \\
-    maybe_dispose(p); \\
-    free(SOD_INSTBASE(obj)); \- \\
-  \}
-\end{prog}
-
 %%%--------------------------------------------------------------------------
 \section{Metaclasses} \label{sec:concepts.metaclasses}
 
