X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/62f9852b653ff96c776418da9492ea644e4a23cf..1edb774eed8bea3f6dbde5b02db6ecd209394cf8:/doc/structures.tex diff --git a/doc/structures.tex b/doc/structures.tex index 029f34c..01e1ecd 100644 --- a/doc/structures.tex +++ b/doc/structures.tex @@ -30,10 +30,16 @@ 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 @||. -The definitions described in sections \ref{sec:structures.layout} are defined -in the header file generated by the containing module. +The concrete types described in +\xref[\instead{sections}]{sec:structures.common} and +\ref{sec:structures.root} are declared by the header file +@||.\footnote{% + This isn't completely true. The @|SodObject| and @|SodClass| structures + are defined in a header called @||, which is generated by + the Sod translator; but @|| includes @||, 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. %%%-------------------------------------------------------------------------- \section{Common instance structure} \label{sec:structures.common} @@ -43,23 +49,37 @@ As described below, a pointer to an instance actually points to an structure. Instance chains contain slots and vtable pointers, as described below. All -instances have the basic structure of a @|struct sod_instance|, which has the -following member. -\begin{description} \let\makelabel\code -\item[const struct sod_vtable *_vt] A pointer to a \emph{vtable}, which has - the basic structure of a @|struct sod_vtable|, described below. -\end{description} - -A vtable contains static metadata needed for efficient conversions and -message dispatch, and pointers to the instance's class. Each chain points to -a different vtable. All vtables have the basic structure of a @|struct -sod_vtable|, which has the following members. -\begin{description} \let\makelabel\code -\item[const SodClass *_class] A pointer to the instance's class object. -\item[size_t _base] The offset of this chain structure above the start of the - overall instance layout, in bytes. Subtracting @|_base| from the instance - chain pointer finds the layout base address. -\end{description} +instances have the basic structure of a @|struct sod_instance|. + +\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. + \begin{description} \let\makelabel\code + \item[_vt] A pointer to a \emph{vtable}, which has the basic structure of a + @|struct sod_vtable|, described below. + \end{description} +\end{describe} + +\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 + message dispatch, and pointers to the instance's class. Each chain points + to a different vtable. All vtables have the basic structure of a @|struct + sod_vtable|, which has the following members. + \begin{description} \let\makelabel\code + \item[_class] A pointer to the instance's class object. + \item[_base] The offset of this chain structure above the start of the + overall instance layout, in bytes. Subtracting @|_base| from the + instance chain pointer finds the layout base address. + \end{description} +\end{describe} %%%-------------------------------------------------------------------------- \section{Built-in root objects} \label{sec:structures.root} @@ -73,170 +93,250 @@ 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{prog} - struct SodObject__vt_obj \{ \\ \ind - const SodClass *_class; \\ - size_t _base; \- \\ - \}; - \\[\bigskipamount] - struct SodObject__ilayout \{ \\ \ind - union \{ \\ \ind - struct SodObject__ichain_obj \{ \\ \ind - const struct SodObject__vt_obj *_vt; \- \\ - \}; \- \\ - \} obj; \- \\ - \}; -\end{prog} - -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. - -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. - -\subsection{The SodClass class} \label{sec:structures.root.sodclass} - -\begin{prog} - struct SodClass__vt_obj \{ \\ \ind - const SodClass *_class; \\ - size_t _base; \- \\ - \}; - \\[\bigskipamount] - struct SodObject__ilayout \{ \\ \ind - union \{ \\ \ind - struct SodClass__ichain_obj \{ \\ \ind - const struct SodClass__vt_obj *_vt; \\ - struct SodClass__islots \{ \\ \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; \\ - 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; \- \\ - \} cls; \- \\ - \}; \\ - SodObject obj; \- \\ - \} obj; \- \\ - \}; -\end{prog} - -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 slots defined are as follows. -\begin{description} \let\makelabel\code - -\item[const char *name] A pointer to the class's name. - -\item[const char *nick] A pointer to the class's nickname. - -\item[size_t initsz] The size in bytes required to store an instance of the - class. - -\item[void *(*imprint)(void *@

)] A pointer to a function: given a pointer - @

to at least @ bytes of appropriately aligned memory, `imprint' - this memory it so that it becomes a minimally functional instance of the - class: all of the vtable and class pointers are properly initialized, but - the slots are left untouched. The function returns its argument @

. - -\item[void *(*init)(void *@

)] 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[size_t n_supers] The number of direct superclasses. (This is zero - exactly in the case of @|SodObject|.) - -\item[const SodClass *const *supers] A pointer to an array of @ - pointers to class objects listing the class's direct superclasses, in the - order in which they were listed in the class definition. If @ is - zero, then this pointer is null. +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}). -\item[size_t n_cpl] The number of superclasses in the class's class - precedence list. -\item[const SodClass *const *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 $c$. - -\item[const SodClass *link] If the class is a chain head, then this is a null - pointer; otherwise it points to the class's distinguished link superclass - (which might or might not be a direct superclass). - -\item[const SodClass *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|$. - -\item[size_t 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$. - -\item[size_t n_chains] -The number of chains formed by the class's superclasses. - -\item[const struct sod_chain *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$. - -\item[size_t off_islots] The offset of the class's @|islots| structure - relative to its containing @|ichain| structure. The class doesn't define - any slots if and only if this is zero. (The offset can't be zero because - the vtable pointer is at offset zero.) - -\item[size_t islotsz] The size required to store the class's direct slots, - i.e., the size of its @|islots| structure. The class doesn't define any - slots if and only if this is zero. +\subsection{The SodObject class} \label{sec:structures.root.sodobject} -\end{description} +\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; \-\\ + \}; + \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); \\ + int (*teardown)(SodObject *me); \-\\ + \} obj; \-\\ + \}; + \end{nprog} \\ + \end{tabular} + \caption{Instance and vtable layout of @|SodObject|} + \label{fig:structures.root.sodobject} +\end{figure} + +\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 + direct superclasses, there is only one chain, and no inherited slots or + messages, so the single chain contains only a vtable pointer. + + 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}{msg}[obj.init]{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}{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} -The -@|struct sod_chain| -structure describes an individual chain of superclasses. -It has the following members. -\begin{description} \let\makelabel\code -\item[size_t n_classes] The number of classes in the chain. This is always - at least one. +\subsection{The SodClass class} \label{sec:structures.root.sodclass} -\item[const SodClass *const *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 < - @$. +\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 *@

); \\ + 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 + 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 + + \item[name] A pointer to the class's name. + + \item[nick] A pointer to the class's nickname. + + \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 @

to at least + @ bytes of appropriately aligned memory, `imprint' this memory it + so that it becomes a minimally functional instance of the class: all of + the vtable and class pointers are properly initialized, but the 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|.) + + \item[supers] A pointer to an array of @ pointers to class + objects listing the class's direct superclasses, in the order in which + they were listed in the class definition. If @ is zero, then + this pointer is null. + + \item[n_cpl] The number of superclasses in the class's class precedence + list. + + \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 + $c$. + + \item[link] If the class is a chain head, then this is a null pointer; + otherwise it points to the class's distinguished link superclass (which + 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|$. + + \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$. + + \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$. + + \item[off_islots] The offset of the class's @|islots| structure relative to + its containing @|ichain| structure. The class doesn't define any slots + if and only if this is zero. (The offset can't be zero because the + vtable pointer is at offset zero.) + + \item[islotsz] The size required to store the class's direct slots, i.e., + the size of its @|islots| structure. The class doesn't define any slots + if and only if this is zero. + + \end{description} +\end{describe} + +\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 + superclasses. It has the following members. + \begin{description} \let\makelabel\code + + \item[n_classes] The number of classes in the chain. This is always at + least one. + + \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 < + @$. -\item[size_t off_ichain] The size of the @|ichain| structure for this chain. + \item[off_ichain] The size of the @|ichain| structure for this chain. -\item[const struct sod_vtable *vt] The vtable for this chain. (It is - possible, therefore, to duplicate the behaviour of the @ function - by walking the chain structure. The @ function is much faster, - though.) + \item[vt] The vtable for this chain. (It is possible, therefore, to + partially duplicate the behaviour of the @ function by walking + the chain structure.\footnote{% + There isn't enough information readily available to fill in the class + pointers correctly.} % + The @ function is much faster, though.) -\item[size_t ichainsz] The size of the @|ichain| structure for this chain. + \item[ichainsz] The size of the @|ichain| structure for this chain. -\end{description} + \end{description} +\end{describe} %%%-------------------------------------------------------------------------- \section{Class and vtable layout} \label{sec:structures.layout} @@ -255,6 +355,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} @@ -262,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 - @_1 @_1; \\ - \quad$\vdots$ \\ - @_n @_n; \- \\ - \} $c$; \- \\ - \} $c$; \\ - struct $H$__ichain_$h$ $h$; \\ - \quad$\vdots$ \- \\ - \} $h$; \\ - union $B$__ichainu_$i$ $i$; \\ - \quad$\vdots$ \- \\ - \}; - \\[\bigskipamount] + 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 + @_1 @_1; \\ + \quad$\vdots$ \\ + @_n @_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} @@ -291,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 @@ -320,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} @@ -345,6 +445,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 @@ -355,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 - @ (*@)($C$ *, $\dots$); \\ - \quad$\vdots$ \- \\ - \} $a$; \\ - \quad$\vdots$ \- \\ - \} $c$; \- \\ - \}; - \\[\bigskipamount] + 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 + @ (*@)($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} @@ -396,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} @@ -446,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. @@ -498,18 +594,28 @@ 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$, + @_{n'} @_{n'} @[= @_{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 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); \\ + @_n @_n, \dots); \\ @_0 $m$__v($C$ *me, @_1 @_1, $\ldots$, @_n @_n, va_list sod__ap); \end{prog} -\subsection{Additional definitions} \label{sec:structures.additional} + +\subsection{Additional definitions} \label{sec:structures.layout.additional} In addition to the instance and vtable structures described above, the following definitions are made for each class $C$. @@ -521,10 +627,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$, @) @@ -542,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 --------------------------------------------------