X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/b8101b235df24885fe5152719ba4a94d214cdd47..a42893dda5f4dd2b89fbfe4e497da261159225ca:/doc/structures.tex diff --git a/doc/structures.tex b/doc/structures.tex index a7be325..42739ef 100644 --- a/doc/structures.tex +++ b/doc/structures.tex @@ -32,8 +32,8 @@ 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 @||. -The definitions described in sections \ref{sec:structures.layout} are defined -in the header file generated by the containing module. +The definitions described in \xref{sec:structures.layout} are defined in the +header file generated by the containing module. %%%-------------------------------------------------------------------------- \section{Common instance structure} \label{sec:structures.common} @@ -87,57 +87,124 @@ metaclass, and @|SodClass| is a subclass of @|SodObject|. Extensions can define additional root classes, but this is tricky, and not really to be recommended. + \subsection{The SodObject class} \label{sec:structures.root.sodobject} \begin{figure}[tbp] \begin{tabular}{p{10pt}p{10pt}} - \begin{prog} + \begin{nprog} struct SodObject__ilayout \{ \\ \ind union \{ \\ \ind struct SodObject__ichain_obj \{ \\ \ind const struct SodObject__vt_obj *_vt; \- \\ - \}; \- \\ + \} obj; \- \\ \} obj; \- \\ \}; - \end{prog} + \end{nprog} & - \begin{prog} + \begin{nprog} struct SodObject__vt_obj \{ \\ \ind const SodClass *_class; \\ - size_t _base; \- \\ + 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{prog} \\ + \end{nprog} \\ \end{tabular} \caption{Instance and vtable layout of @|SodObject|} \label{fig:structures.root.sodobject} \end{figure} \begin{describe}[SodObject]{cls} - {[metaclass = SodClass, lisp_metaclass = sod_class] \\ - class SodObject \{ \}} + {[nick = obj, metaclass = SodClass, lisp_metaclass = sod_class] \\ + class SodObject \{ \\ \ind + void init(?); + \}} - The @|SodObject| class defines no slots or messages. Because @|SodObject| - has no direct superclasses, there is only one chain, and no inherited - slots or messages, so the single chain contains only a vtable pointer. + The @|SodObject| class defines no slots. Because @|SodObject| has no + direct superclasses, there is only one chain, and no inherited slots or + messages, so the single chain contains only a vtable pointer. - Since there are no messages, and @|SodClass| also has only one chain, the - vtable contains only the standard class pointer and offset-to-base members. - In a direct instance of @|SodObject| (why would you want one?) the class - pointer contains the address of @|SodObject__class| and the offset is zero. + Since @|SodClass| also has only one chain, the vtable contains only the + standard class pointer and offset-to-base members. In a direct instance of + @|SodObject| (why would you want one?) the class pointer contains the + address of @|SodObject__class| and the offset is zero. The instance and vtable layout of @|SodObject| is shown in \xref{fig:structures.root.sodobject}. + + The following messages are defined. + + \begin{describe}[obj.init]{msg}{void init(?);} + Initialize a newly allocated instance. + + This message uses a custom method combination which works like the + standard method combination except that default behaviour specific to the + receiver's direct class is invoked if no primary or around method + overrides. This default behaviour may be invoked multiple times if some + 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, 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 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. + + It is usual to provide complex initialization behaviour as @|after| + methods. This ensures that slots have been initialized as necessary + before the method executes. + + For more details on instance construction, see + \xref{sec:concepts.lifecycle.birth}. + \end{describe} + + \begin{describe}[obj.teardown]{msg}{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} - {class SodClass : SodObject \{ \\ \ind + {[nick = cls, link = SodObject] \\ + class SodClass : SodObject \{ \\ \ind const char *name; \\ const char *nick; \\ size_t initsz; \\ void *(*imprint)(void *@

); \\ - void *(*init)(void *@

); \\ size_t n_supers; \\ const SodClass *const *supers; \\ size_t n_cpl; \\ @@ -151,9 +218,9 @@ recommended. size_t islotsz; \- \\ \}} - The @|SodClass| class defines no messages, but there are a number of slots. - Its only direct superclass is @|SodObject| and so (like its superclass) its - vtable is trivial. + The @|SodClass| class defines no additional messages , but there are a + number of slots. Its only direct superclass is @|SodObject| and so (like + its superclass) its vtable is simple. The slots defined are as follows. \begin{description} \let\makelabel\code @@ -170,12 +237,6 @@ recommended. the vtable and class pointers are properly initialized, but the slots are left untouched. The function returns its argument @

. - \item[init] A pointer to a function: given a pointer @

to at least - @ bytes of appropriately aligned memory, initialize an instance - of the class in it: all of the vtable and class pointers are initialized, - as are slots for which initializers are defined. Other slots are left - untouched. The function returns its argument @

. - \item[n_supers] The number of direct superclasses. (This is zero exactly in the case of @|SodObject|.) @@ -189,7 +250,7 @@ recommended. \item[cpl] A pointer to an array of pointers to class objects listing all of the class's superclasses, from most- to least-specific, starting with - the class itself, so $c@->@|cls|.@|cpl|[0] = c$ for all class objects + the class itself, so $@|$c$@->cls.cpl[0]| = c$ for all class objects $c$. \item[link] If the class is a chain head, then this is a null pointer; @@ -197,21 +258,20 @@ recommended. might or might not be a direct superclass). \item[head] A pointer to the least-specific class in this class's chain; so - $c@->@|cls|.@|head|@->@|cls|.@|link|$ is always null, and either - $c@->@|cls|.@|link|$ is null (in which case $c@->@|cls|.@|head| = c$) or - $c@->@|cls|.@|head| = c@->@|cls|.@|link|@->@|cls|.@|head|$. + @|$c$@->cls.head@->cls.link| is always null, and either @|$c$@->cls.link| + is null (in which case $@|$c$@->cls.head| = c$) or $@|$c$@->cls.head| = + @|$c$@->cls.link@->cls.head|$. \item[level] The number of less specific superclasses in this class's - chain. If $c@->@|cls|.@|link|$ is null then $c@->@|cls|.@|level|$ is - zero; otherwise $c@->@|cls|.@|level| = - c@->@|cls|.@|link|@->@|cls|.@|level| + 1$. + chain. If @|$c$@->cls.link| is null then @|$c$@->cls.level| is zero; + otherwise $@|$c$@->cls.level| = @|$c$@->cls.link@->cls.level| + 1$. \item[n_chains] The number of chains formed by the class's superclasses. \item[chains] A pointer to an array of @|struct sod_chain| structures (see below) describing the class's superclass chains, in decreasing order of specificity of their most specific classes. It is always the case that - $c@->@|cls|.@|chains|[0].@|classes|[c@->@|cls|.@|level|] = c$. + $@|$c$@->cls.chains[0].classes[$c$@->cls.level]| = c$. \item[off_islots] The offset of the class's @|islots| structure relative to its containing @|ichain| structure. The class doesn't define any slots @@ -243,9 +303,9 @@ recommended. \item[classes] A pointer to an array of class pointers listing the classes in the chain from least- to most-specific. So - $@[i]@->@|cls|.@|head| = @[0]$ for all $0 \le i < - @$, $@[0]@->@|cls|.@|link|$ is always null, and - $@[i]@->@|cls|.@|link| = @[i - 1]$ if $1 \le i < + $@|@[$i$]@->cls.head| = @|@[0]|$ for all $0 \le i < + @$, @|@[0]@->cls.link| is always null, and + $@|@[$i$]@->cls.link| = @|@[$i - 1$]|$ if $1 \le i < @$. \item[off_ichain] The size of the @|ichain| structure for this chain. @@ -279,6 +339,7 @@ In the description that follows, uppercase letters vary over class names, while the corresponding lowercase letters indicate the class nicknames. Throughout, we consider a class $C$ (therefore with nickname $c$). + \subsection{Generic instance structure} \label{sec:structures.layout.instance} @@ -304,7 +365,7 @@ type @|struct $C$__ilayout|. union $B$__ichainu_$i$ $i$; \\ \quad$\vdots$ \- \\ \}; - \\[\bigskipamount] + \\+ typedef struct $C$__ichain_$h$ $C$; \end{prog} @@ -369,6 +430,7 @@ type system) to be a pointer to the @|struct $C$__ichain_$h$|. Finally, the @|islots| structure simply contains one member for each slot defined by $C$ in the order they appear in the class definition. + \subsection{Generic vtable structure} \label{sec:structures.layout.vtable} As described above, each @|ichain| structure of an instance's storage has a @@ -408,7 +470,7 @@ structure. \quad$\vdots$ \- \\ \} $c$; \- \\ \}; - \\[\bigskipamount] + \\+ extern const union $C$__vtu_$h$ $C$__vtable_$h$; \end{prog} @@ -522,10 +584,16 @@ defined as \begin{prog} @_0 $m$(@_1 @_1, $\ldots$, @_n @_n, \dots); \end{prog} +or a standard message which takes keyword arguments, defined as +\begin{prog} + @_0 $m$(\=@_1 @_1, $\ldots$, @_n @_n? \+ \\ + @_{n+1} @_{n+1} @[= @_{n+1}@], $\ldots$, + @_m @_m @[= @_m@]); +\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 argument of type @|va_list| in place of the variable portion of the argument -list. +list or keywords. \begin{prog} @_0 $m$($C$ *me, @_1 @_1, $\ldots$, @_n @_n, \dots); \\ @@ -533,6 +601,7 @@ list. @_n @_n, va_list sod__ap); \end{prog} + \subsection{Additional definitions} \label{sec:structures.layout.additional} In addition to the instance and vtable structures described above, the @@ -545,10 +614,10 @@ For each message $m$ directly defined by $C$ there is a macro definition which makes sending the message $m$ to an instance of (any subclass of) $C$ somewhat less ugly. -If $m$ takes a variable number of arguments, the macro is more complicated -and is only available in compilers advertising C99 support, but the effect is -the same. For each variable-argument message, there is also an additional -macro for calling the `valist' entry point. +If $m$ takes a variable number of arguments, or keyword arguments, the macro +is more complicated and is only available in compilers advertising C99 +support, but the effect is the same. For each variable-argument message, +there is also an additional macro for calling the `valist' entry point. \begin{prog} \#define $C$_$m$__v(@, $\ldots$, @) @@->_vt@->$c$.$m$__v(@, $\ldots$, @)