X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/71efc5247bf809b4941b88e3b3182e181e6a20ab..53045abe97d43dcabb4be9268cb9d4b2727ae437:/doc/concepts.tex

diff --git a/doc/concepts.tex b/doc/concepts.tex
index b452f3c..8e774fe 100644
--- a/doc/concepts.tex
+++ b/doc/concepts.tex
@@ -63,22 +63,33 @@ having to implement additional syntax.
 For the most part, Sod takes a fairly traditional view of what it means to be
 an object system.
 
-An \emph{object} maintains \emph{state} and exhibits \emph{behaviour}.  An
-object's state is maintained in named \emph{slots}, each of which can store a
-C value of an appropriate (scalar or aggregate) type.  An object's behaviour
-is stimulated by sending it \emph{messages}.  A message has a name, and may
-carry a number of arguments, which are C values; sending a message may result
-in the state of receiving object (or other objects) being changed, and a C
-value being returned to the sender.
-
-Every object is a (direct) instance of some \emph{class}.  The class
-determines which slots its instances have, which messages its instances can
-be sent, and which methods are invoked when those messages are received.  The
-Sod translator's main job is to read class definitions and convert them into
-appropriate C declarations, tables, and functions.  An object cannot
+An \emph{object} maintains \emph{state} and exhibits \emph{behaviour}.
+(Here, we're using the term `object' in the usual sense of `object-oriented
+programming', rather than that of the ISO~C standard.  Once we have defined
+an `instance' below, we shall generally prefer that term, so as to prevent
+further confusion between these two uses of the word.)
+
+An object's state is maintained in named \emph{slots}, each of which can
+store a C value of an appropriate (scalar or aggregate) type.  An object's
+behaviour is stimulated by sending it \emph{messages}.  A message has a name,
+and may carry a number of arguments, which are C values; sending a message
+may result in the state of receiving object (or other objects) being changed,
+and a C value being returned to the sender.
+
+Every object is a \emph{direct instance} of exactly one \emph{class}.  The
+class determines which slots its instances have, which messages its instances
+can be sent, and which methods are invoked when those messages are received.
+The Sod translator's main job is to read class definitions and convert them
+into appropriate C declarations, tables, and functions.  An object cannot
 (usually) change its direct class, and the direct class of an object is not
 affected by, for example, the static type of a pointer to it.
 
+If an object~$x$ is a direct instance of some class~$C$, then we say that $C$
+is \emph{the class of}~$x$.  Note that the class of an object is a property
+of the object's value at runtime, and not of C's compile-time type system.
+We shall be careful in distinguishing C's compile-time notion of \emph{type}
+from Sod's run-time notion of \emph{class}.
+
 
 \subsection{Superclasses and inheritance}
 \label{sec:concepts.classes.inherit}
@@ -120,22 +131,22 @@ class then the only superclass of $C$ is $C$ itself, and $C$ has no proper
 superclasses.
 
 If an object is a direct instance of class~$C$ then the object is also an
-(indirect) instance of every superclass of $C$.
+(indirect) \emph{instance} of every superclass of $C$.
 
 If $C$ has a proper superclass $B$, then $B$ must not have $C$ as a direct
-superclass.  In different terms, if we construct a graph, whose vertices are
-classes, and draw an edge from each class to each of its direct superclasses,
-then this graph must be acyclic.  In yet other terms, the `is a superclass
-of' relation is a partial order on classes.
+superclass.  In different terms, if we construct a directed graph, whose
+nodes are classes, and draw an arc from each class to each of its direct
+superclasses, then this graph must be acyclic.  In yet other terms, the `is a
+superclass of' relation is a partial order on classes.
 
 \subsubsection{The class precedence list}
 This partial order is not quite sufficient for our purposes.  For each class
 $C$, we shall need to extend it into a total order on $C$'s superclasses.
 This calculation is called \emph{superclass linearization}, and the result is
 a \emph{class precedence list}, which lists each of $C$'s superclasses
-exactly once.  If a superclass $B$ precedes (resp.\ follows) some other
-superclass $A$ in $C$'s class precedence list, then we say that $B$ is a more
-(resp.\ less) \emph{specific} superclass of $C$ than $A$ is.
+exactly once.  If a superclass $B$ precedes or follows some other superclass
+$A$ in $C$'s class precedence list, then we say that $B$ is respectively a
+more or less \emph{specific} superclass of $C$ than $A$.
 
 The superclass linearization algorithm isn't fixed, and extensions to the
 translator can introduce new linearizations for special effects, but the
@@ -148,8 +159,8 @@ following properties are expected to hold.
   list, i.e., $B$ is a more specific superclass of $C$ than $A$ is.
 \end{itemize}
 The default linearization algorithm used in Sod is the \emph{C3} algorithm,
-which has a number of good properties described in~\cite{Barrett:1996:MSL}.
-It works as follows.
+which has a number of good properties described
+in~\cite{barrett-1996:monot-super-linear-dylan}.  It works as follows.
 \begin{itemize}
 \item A \emph{merge} of some number of input lists is a single list
   containing each item that is in any of the input lists exactly once, and no
@@ -237,23 +248,24 @@ It works as follows.
     $\langle C, @|SodObject| \rangle$.  The class precedence list begins
     $\langle G, E, \ldots \rangle$, but the individual lists don't order $A$
     and $C$.  Comparing these to $G$'s direct superclasses, we see that $A$
-    is a subclass of $E$, while $C$ is a subclass of -- indeed equal to --
-    $C$; so $A$ must precede $C$, as must $B$, and the final list is $\langle
-    G, E, A, B, C, @|SodObject| \rangle$.
+    is a superclass of $E$, while $C$ is a superclass of -- indeed equal to
+    -- $C$; so $A$ must precede $C$, as must $B$, and the final list is
+    $\langle G, E, A, B, C, @|SodObject| \rangle$.
 
   \item Finally, we determine $I$'s class precedence list by merging $\langle
     I, G, H \rangle$, $\langle G, E, A, B, C, @|SodObject| \rangle$, and
     $\langle H, F, A, D, @|SodObject| \rangle$.  The list begins $\langle I,
     G, \ldots \rangle$, and then we must break a tie between $E$ and $H$; but
-    $E$ is a subclass of $G$, so $E$ wins.  Next, $H$ and $F$ must precede
+    $E$ is a superclass of $G$, so $E$ wins.  Next, $H$ and $F$ must precede
     $A$, since these are ordered by $H$'s class precedence list.  Then $B$
     and $C$ precede $D$, since the former are superclasses of $G$, and the
     final list is $\langle I, G, E, H, F, A, B, C, D, @|SodObject| \rangle$.
 
   \end{itemize}
 
-  (This example combines elements from \cite{Barrett:1996:MSL} and
-  \cite{Ducournau:1994:PMM}.)
+  (This example combines elements from
+  \cite{barrett-1996:monot-super-linear-dylan} and
+  \cite{ducournau-1994:monot-multip-inher-linear}.)
 \end{example}
 
 \subsubsection{Class links and chains}
@@ -276,6 +288,7 @@ class in a chain is called the \emph{chain head}; the most specific class is
 the \emph{chain tail}.  Chains are often named after their chain head
 classes.
 
+
 \subsection{Names}
 \label{sec:concepts.classes.names}
 
@@ -301,13 +314,14 @@ qualified by the defining class's nickname.
 \subsubsection{Slot initializers}
 As well as defining slot names and types, a class can also associate an
 \emph{initial value} with each slot defined by itself or one of its
-subclasses.  A class $C$ provides an \emph{initialization message} (see
-\xref{sec:concepts.lifecycle.birth}, and \xref{sec:structures.root.sodclass})
-whose methods set the slots of a \emph{direct} instance of the class to the
-correct initial values.  If several of $C$'s superclasses define initializers
-for the same slot then the initializer from the most specific such class is
-used.  If none of $C$'s superclasses define an initializer for some slot then
-that slot will be left uninitialized.
+superclasses.  A class $C$ provides an \emph{initialization message} (see
+\xref[\instead{sections}]{sec:concepts.lifecycle.birth}, and
+\ref{sec:structures.root.sodobject}) whose methods set the slots of a
+\emph{direct} instance of the class to the correct initial values.  If
+several of $C$'s superclasses define initializers for the same slot then the
+initializer from the most specific such class is used.  If none of $C$'s
+superclasses define an initializer for some slot then that slot will be left
+uninitialized.
 
 The initializer for a slot with scalar type may be any C expression.  The
 initializer for a slot with aggregate type must contain only constant
@@ -333,6 +347,9 @@ details.
 
 \subsection{C language integration} \label{sec:concepts.classes.c}
 
+It is very important to distinguish compile-time C \emph{types} from Sod's
+run-time \emph{classes}: see \xref{sec:concepts.classes}.
+
 For each class~$C$, the Sod translator defines a C type, the \emph{class
 type}, with the same name.  This is the usual type used when considering an
 object as an instance of class~$C$.  No entire object will normally have a
@@ -342,6 +359,10 @@ class type,\footnote{%
   chains.  See \xref{sec:structures.layout} for the full details.} %
 so access to instances is almost always via pointers.
 
+Usually, a value of type pointer-to-class-type of class~$C$ will point into
+an instance of class $C$.  However, clever (or foolish) use of pointer
+conversions can invalidate this relationship.
+
 \subsubsection{Access to slots}
 The class type for a class~$C$ is actually a structure.  It contains one
 member for each class in $C$'s superclass chain, named with that class's
@@ -349,8 +370,14 @@ nickname.  Each of these members is also a structure, containing the
 corresponding class's slots, one member per slot.  There's nothing special
 about these slot members: C code can access them in the usual way.
 
-For example, if @|MyClass| has the nickname @|mine|, and defines a slot @|x|
-of type @|int|, then the simple function
+For example, given the definition
+\begin{prog}
+  [nick = mine]                                                 \\
+  class MyClass: SodObject \{                                   \\ \ind
+    int x;                                                    \-\\
+  \}
+\end{prog}
+the simple function
 \begin{prog}
   int get_x(MyClass *m) \{ return (m@->mine.x); \}
 \end{prog}
@@ -363,6 +390,11 @@ to it in a slot.  (This will also help preserve binary compatibility, because
 the private structure can grow more members as needed.  See
 \xref{sec:concepts.compatibility} for more details.)
 
+Slots defined by $C$'s link superclass, or any other superclass in the same
+chain, can be accessed in the same way.  Slots defined by other superclasses
+can't be accessed directly: the instance pointer must be \emph{converted} to
+point to a different chain.  See the subsection `Conversions' below.
+
 
 \subsubsection{Sending messages}
 Sod defines a macro for each message.  If a class $C$ defines a message $m$,
@@ -442,12 +474,12 @@ There are three main cases to distinguish.
   a lookup at runtime to find the appropriate offset by which to adjust the
   pointer.  The conversion can be performed using the appropriate generated
   upcast macro (see below); the general case is handled by the macro
-  \descref{SOD_XCHAIN}{mac}.
+  \descref{mac}{SOD_XCHAIN}.
 \item If $B$ is a subclass of~$C$ then the conversion is a \emph{downcast};
   otherwise the conversion is a~\emph{cross-cast}.  In either case, the
   conversion can fail: the object in question might not be an instance of~$B$
-  after all.  The macro \descref{SOD_CONVERT}{mac} and the function
-  \descref{sod_convert}{fun} perform general conversions.  They return a null
+  after all.  The macro \descref{mac}{SOD_CONVERT} and the function
+  \descref{fun}{sod_convert} perform general conversions.  They return a null
   pointer if the conversion fails.  (These are therefore your analogue to the
   \Cplusplus\ @|dynamic_cast<>| operator.)
 \end{itemize}
@@ -504,6 +536,13 @@ Keyword arguments can be provided in three ways.
   call, which is useful when writing wrapper functions.
 \end{enumerate}
 
+Perhaps surprisingly, keyword arguments have a relatively small performance
+impact.  On the author's aging laptop, a call to a simple function, passing
+two out of three keyword arguments, takes about 30 cycles longer than calling
+a standard function which just takes integer arguments.  On the other hand,
+quite a lot of code is involved in decoding keyword arguments, so code size
+will naturally suffer.
+
 Keyword arguments are provided as a general feature for C functions.
 However, Sod has special support for messages which accept keyword arguments
 (\xref{sec:concepts.methods.keywords}); and they play an essential rÃ´le in
@@ -569,9 +608,9 @@ message.  The method combination determines which direct method rÃ´les are
 acceptable, and, for each rÃ´le, the appropriate argument lists and return
 types.
 
-One direct method, $M$, is said to be more (resp.\ less) \emph{specific} than
+One direct method, $M$, is said to be more or less \emph{specific} than
 another, $N$, with respect to a receiving class~$C$, if the class defining
-$M$ is a more (resp.\ less) specific superclass of~$C$ than the class
+$M$ is respectively a more or less specific superclass of~$C$ than the class
 defining $N$.
 
 \subsubsection{The standard method combination}
@@ -657,7 +696,7 @@ entry functions.
       node [above right = 0mm and -8mm]
       {$\vcenter{\hbox{\Huge\textcolor{red}{!}}}
         \vcenter{\hbox{\begin{tabular}[c]{l}
-                         \textsf{next_method} \\
+                         @|next_method| \\
                          pointer is null
                        \end{tabular}}}$};
 
@@ -782,7 +821,7 @@ The aggregating method combinations provided are as follows.
 \item[progn] The message must return @|void|.  The applicable primary methods
   are simply invoked in turn, most specific first.
 \item[sum] The message must return a numeric type.\footnote{%
-    The Sod translator does not check this, since it doesn't have enough
+    The Sod translator doesn't check this, since it doesn't have enough
     insight into @|typedef| names.} %
   The applicable primary methods are invoked in turn, and their return values
   added up.  The final result is the sum of the individual values.
@@ -812,8 +851,6 @@ in \xref{sec:fixme.custom-aggregating-method-combination}.
 
 \subsection{Method entries} \label{sec:concepts.methods.entry}
 
-Each instance is associated with its direct class \fixme{direct instances}
-
 The effective methods for each class are determined at translation time, by
 the Sod translator.  For each effective method, one or more \emph{method
 entry functions} are constructed.  A method entry function has three
@@ -852,11 +889,10 @@ While method combinations may set their own rules, usually keyword methods
 can only be defined on keyword messages, and all methods defined on a keyword
 message must be keyword methods.  The direct methods defined on a keyword
 message may differ in the keywords they accept, both from each other, and
-from the message.  If two superclasses of some common class both define
-keyword methods on the same message, and the methods both accept a keyword
-argument with the same name, then these two keyword arguments must also have
-the same type.  Different applicable methods may declare keyword arguments
-with the same name but different defaults; see below.
+from the message.  If two applicable methods on the same message both accept
+a keyword argument with the same name, then these two keyword arguments must
+also have the same type.  Different applicable methods may declare keyword
+arguments with the same name but different defaults; see below.
 
 The keyword arguments acceptable in a message sent to an object are the
 keywords listed in the message definition, together with all of the keywords
@@ -889,14 +925,14 @@ Construction of a new instance of a class involves three steps.
   instance's slots, and maybe links it into any external data structures as
   necessary.
 \end{enumerate}
-The \descref{SOD_DECL}[macro]{mac} handles constructing instances with
+The \descref{mac}{SOD_DECL}[macro] handles constructing instances with
 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
+\descref{mac}{SOD_MAKE}[macro] and the \descref*{fun}{sod_make} and
+\descref{fun}{sod_makev} 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.
+strategies by using the \descref{mac}{SOD_INIT}[macro] and the
+\descref*{fun}{sod_init} and \descref{fun}{sod_initv} functions, which
+package up imprinting and initialization.
 
 \subsubsection{Allocation}
 Instances of most classes (specifically including those classes defined by
@@ -905,7 +941,8 @@ layout of an instance of some class~$C$ is described by the type @|struct
 $C$__ilayout|, and if the relevant class is known at compile time then the
 best way to discover the layout size is with the @|sizeof| operator.  Failing
 that, the size required to hold an instance of $C$ is available in a slot in
-$C$'s class object, as @|$C$__class@->cls.initsz|.
+$C$'s class object, as @|$C$__class@->cls.initsz|.  The necessary alignment,
+in bytes, is provided as @|$C$__class@->cls.align|, should this be necessary.
 
 It is not in general sufficient to declare, or otherwise allocate, an object
 of the class type $C$.  The class type only describes a single chain of the
@@ -921,10 +958,6 @@ instances, so, for example, Sod doesn't make using fancy allocators which
 sometimes move objects around in memory any more difficult than it needs to
 be.
 
-There isn't any way to discover the alignment required for a particular
-class's instances at runtime; it's best to be conservative and assume that
-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}
@@ -1012,7 +1045,8 @@ defines a name, type, and (optionally) a default value for the initarg.
 slot or slot initializer item: the property's value 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.
+containing class.  (Note that a slot may have any number of slot initargs;
+and any number of slots may have initargs with the same name.)
 
 Initargs are inherited.  The \emph{applicable} direct initargs for an @|init|
 effective method are those defined by the receiving object's class, and all
@@ -1033,15 +1067,21 @@ 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.
+  corresponding effective initargs, then the value of the most specific such
+  initarg is stored in the slot.  (For this purpose, initargs defined earlier
+  in a class definition are more specific than initargs defined later.)
+
 \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.
+  slot.  (A class may define at most one initializer for any particular slot,
+  so no further disambiguation is required.)
+
 \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.
@@ -1061,9 +1101,9 @@ steps.
 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
+using the \descref{fun}{sod_teardown}[function].  Destruction of instances
 allocated from the standard @|malloc| heap is done using the
-\descref{sod_destroy}[function]{fun}.
+\descref{fun}{sod_destroy}[function].
 
 \subsubsection{Teardown}
 Details of teardown are necessarily class-specific, but typically it
@@ -1088,7 +1128,7 @@ counting system, as follows.
     [role = around]                                             \\
     int obj.teardown()                                          \\
     \{                                                          \\ \ind
-      if (--\,--me@->ref.nref) return (1);                      \\
+      if (@--me@->ref.nref) return (1);                           \\
       else return (CALL_NEXT_METHOD);                         \-\\
     \}                                                        \-\\
   \}
@@ -1121,7 +1161,7 @@ class.
 The code which makes the decision to destroy an object may often not be aware
 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}.
+determined using the \descref{mac}{SOD_INSTBASE}[macro].
 
 %%%--------------------------------------------------------------------------
 \section{Metaclasses} \label{sec:concepts.metaclasses}
@@ -1227,9 +1267,35 @@ the minimal $M_j$.
 \subsection{Translation-time metaobjects}
 \label{sec:concepts.metaclasses.compile-time}
 
+Within the translator, modules, classes, slots and initializers, messages and
+methods are all represented as instances of classes.  Since the translator is
+written in Common Lisp, these translation-time metaobject classes are all
+CLOS classes.  Extensions can influence the translator's behaviour -- and
+hence the layout and behaviour of instances at runtime -- by subclassing the
+built-in metaobject classes and implementing methods on appropriate generic
+functions.
 
-
-\fixme{unwritten}
+Metaobject classes are chosen in a fairly standard way.
+\begin{itemize}
+\item All metaobject definitions support a symbol-valued property, usually
+  named @|@<thing>_class| (e.g., @|slot_class|, @|method_class|), which sets
+  the metaobject class explicitly.  (The class for a class metaobject is
+  taken from the @|lisp_class| property, because @|class_class| seems less
+  meaningful.)
+\item Failing that, the metaobject's parents choose a default metaobject
+  class, based on the new metaobject's properties; i.e., slots and messages
+  have their metaobject classes chosen by the defining class metaobject;
+  initializer and initarg classes are chosen by the defining class metaobject
+  and the direct slot metaobject; and method classes are chosen by the
+  defining class metaobject and the message metaobject.
+\item Classes have no parents; instead, the default is simply to use the
+  builtin metaobject class @|sod-class|.
+\item Modules are a special case because the property syntax is rather
+  awkward.  All modules are initially created as instances of the built-in
+  metaclass @|module|.  Once the module has been parsed completely, the
+  module metaobject's classes is changed, using @|change-class|, to the class
+  specified in the module's property set.
+\end{itemize}
 
 %%%--------------------------------------------------------------------------
 \section{Compatibility considerations} \label{sec:concepts.compatibility}
