chiark / gitweb /
Abandoned atoms work: hardly any performance benefit.
[sod] / src / classes.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Class definitions for main classes
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensible Object Design, an object system for C.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod)
27
28 ;;; Note!  You'll notice that none of the classes defined here store property
29 ;;; sets persistently, even though there's a `:pset' keyword argument
30 ;;; accepted by many of the classes' initialization methods.  That's because
31 ;;; part of the pset protocol involves checking that there are no unused
32 ;;; properties, and this typically happens shortly after the appropriate
33 ;;; objects are constructed.  It would be tempting to stash the pset at
34 ;;; initialization time, and then pick some property from it out later -- but
35 ;;; that won't work in general because an error might have been signalled
36 ;;; about that property.  It wouldn't surprise me greatly to discover that
37 ;;; `most' code paths resulted in the property being looked up in time to
38 ;;; avoid the unused-property error, but a subtle change in circumstances
39 ;;; then causes a thing done on demand to be done later, leading to
40 ;;; irritating and misleading errors being reported to the user.  So please
41 ;;; don't do that.
42
43 ;;;--------------------------------------------------------------------------
44 ;;; Classes.
45
46 (export '(sod-class sod-class-name sod-class-nickname
47           sod-class-type sod-class-metaclass
48           sod-class-direct-superclasses sod-class-precedence-list
49           sod-class-chain-link sod-class-chain-head
50           sod-class-chain sod-class-chains
51           sod-class-slots sod-class-initfrags sod-class-tearfrags
52           sod-class-instance-initializers sod-class-class-initializers
53           sod-class-messages sod-class-methods
54           sod-class-state
55           sod-class-ilayout sod-class-vtables))
56 (defclass sod-class ()
57   ((name :initarg :name :type string :reader sod-class-name)
58    (location :initarg :location :initform (file-location nil)
59              :type file-location :reader file-location)
60    (nickname :initarg :nick :type string :reader sod-class-nickname)
61    (direct-superclasses :initarg :superclasses :type list
62                         :reader sod-class-direct-superclasses)
63    (chain-link :initarg :link :type (or sod-class null)
64                :reader sod-class-chain-link)
65    (metaclass :initarg :metaclass :type sod-class
66               :reader sod-class-metaclass)
67    (slots :initarg :slots :initform nil
68           :type list :accessor sod-class-slots)
69    (instance-initializers :initarg :instance-initializers :initform nil
70                           :type list
71                           :accessor sod-class-instance-initializers)
72    (class-initializers :initarg :class-initializers :initform nil
73                        :type list :accessor sod-class-class-initializers)
74    (initargs :initarg :initargs :initform nil
75              :type list :accessor sod-class-initargs)
76    (initfrags :initarg :initfrags :initform nil
77               :type list :accessor sod-class-initfrags)
78    (tearfrags :initarg :tearfrags :initform nil
79               :type list :accessor sod-class-tearfrags)
80    (messages :initarg :messages :initform nil
81              :type list :accessor sod-class-messages)
82    (methods :initarg :methods :initform nil
83             :type list :accessor sod-class-methods)
84
85    (class-precedence-list :type list :reader sod-class-precedence-list)
86
87    (%type :type c-class-type :reader sod-class-type)
88
89    (chain-head :type sod-class :reader sod-class-chain-head)
90    (chain :type list :reader sod-class-chain)
91    (chains :type list :reader sod-class-chains)
92
93    (%ilayout :type ilayout :reader sod-class-ilayout)
94    (effective-methods :type list :reader sod-class-effective-methods)
95    (vtables :type list :reader sod-class-vtables)
96
97    (state :initform nil :type (member nil :finalized :broken)
98           :reader sod-class-state))
99   (:documentation
100    "Classes describe the layout and behaviour of objects.
101
102    The `name', `location', `nickname', `direct-superclasses', `chain-link'
103    and `metaclass' slots are intended to be initialized when the class object
104    is constructed:
105
106      * The `name' is the identifier associated with the class in the user's
107        source file.  It is used verbatim in the generated C code as a type
108        name, and must be distinct from other file-scope names in any source
109        file which includes the class definition.  Furthermore, other names
110        are derived from the class name (most notably the class object
111        NAME__class), which have external linkage and must therefore be
112        distinct from all other identifiers in the program.  It is forbidden
113        for a class `name' to begin with an underscore or to contain two
114        consecutive underscores.
115
116      * The `location' identifies where in the source the class was defined.
117        It gets used in error messages.
118
119      * The `nickname' is a shorter identifier used to name the class in some
120        circumstances.  The uniqueness requirements on `nickname' are less
121        strict, which allows them to be shorter: no class may have two classes
122        with the same nickname on its class precedence list.  Nicknames are
123        used (user-visibly) to distinguish slots and messages defined by
124        different classes, and (invisibly) in the derived names of direct
125        methods.  It is forbidden for a nickname to begin with an underscore,
126        or to contain two consecutive underscores.
127
128      * The `direct-superclasses' are a list of the class's direct
129        superclasses, in the order that they were declared in the source.  The
130        class precedence list is computed from the `direct-superclasses' lists
131        of all of the superclasses involved.
132
133      * The `chain-link' is either `nil' or one of the `direct-superclasses'.
134        Class chains are a means for recovering most of the benefits of simple
135        hierarchy lost by the introduction of multiple inheritance.  A class's
136        superclasses (including itself) are partitioned into chains,
137        consisting of a class, its `chain-link' superclass, that class's
138        `chain-link', and so on.  It is an error if two direct subclasses of
139        any class appear in the same chain (a global property which requires
140        global knowledge of an entire program's class hierarchy in order to
141        determine sensibly).  Slots of superclasses in the same chain can be
142        accessed efficiently; there is an indirection needed to access slots
143        of superclasses in other chains.  Furthermore, an indirection is
144        required to perform a cross-chain conversion (i.e., converting a
145        pointer to an instance of some class into a pointer to an instance of
146        one of its superclasses in a different chain), an operation which
147        occurs implicitly in effective methods in order to call direct methods
148        defined on cross-chain superclasses.
149
150      * The `metaclass' is the class of the class object.  Classes are objects
151        in their own right, and therefore must be instances of some class;
152        this class is the metaclass.  Metaclasses can define additional slots
153        and methods to be provided by their instances; a class definition can
154        provide (C constant expression) initial values for the metaclass
155        instance.
156
157    The next few slots can't usually be set at object-construction time, since
158    the objects need to contain references to the class object itself.
159
160      * The `slots' are a list of the slots defined by the class (instances of
161        `sod-slot').  (The class will also define all of the slots defined by
162        its superclasses.)
163
164      * The `instance-initializers' and `class-initializers' are lists of
165        initializers for slots (see `sod-initializer' and subclasses),
166        providing initial values for instances of the class, and for the
167        class's class object itself, respectively.
168
169      * The `messages' are a list of the messages recognized by the class
170        (instances of `sod-message' and subclasses).  (Note that the message
171        need not have any methods defined on it.  The class will also
172        recognize all of the messages defined by its superclasses.)
173
174      * The `methods' are a list of (direct) methods defined on the class
175        (instances of `sod-method' and subclasses).  Each method provides
176        behaviour to be invoked by a particular message recognized by the
177        class.
178
179    Other slots are computed from these in order to describe the class's
180    layout and effective methods; this is done by `finalize-sod-class'.
181
182      * The `class-precedence-list' is a list of superclasses in a linear
183        order.  It is computed by `compute-class-precedence-list', whose
184        default implementation ensures that the order of superclasses is such
185        that (a) subclasses appear before their superclasses; (b) the direct
186        superclasses of a given class appear in the order in which they were
187        declared by the programmer; and (c) classes always appear in the same
188        relative order in all class precedence lists in the same superclass
189        graph.
190
191      * The `chain-head' is the least-specific class in the class's chain.  If
192        there is no link class then the `chain-head' is the class itself.
193        This slot, like the next two, is computed by the generic function
194        `compute-chains'.
195
196      * The `chain' is the list of classes on the complete primary chain,
197        starting from this class and ending with the `chain-head'.
198
199      * The `chains' are the complete collection of chains (most-to-least
200        specific) for the class and all of its superclasses.
201
202    Finally, slots concerning the instance and vtable layout of the class are
203    computed on demand (see `define-on-demand-slot').
204
205      * The `ilayout' describes the layout for an instance of the class.  It's
206        quite complicated; see the documentation of the `ilayout' class for
207        detais.
208
209      * The `effective-methods' are a list of effective methods, specialized
210        for the class.
211
212      * The `vtables' are a list of descriptions of vtables for the class.
213        The individual elements are `vtable' objects, which are even more
214        complicated than `ilayout' structures.  See the class documentation
215        for details."))
216
217 (defmethod print-object ((class sod-class) stream)
218   (maybe-print-unreadable-object (class stream :type t)
219     (princ (sod-class-name class) stream)))
220
221 ;;;--------------------------------------------------------------------------
222 ;;; Slots and initializers.
223
224 (export '(sod-slot sod-slot-name sod-slot-class sod-slot-type))
225 (defclass sod-slot ()
226   ((name :initarg :name :type string :reader sod-slot-name)
227    (location :initarg :location :initform (file-location nil)
228              :type file-location :reader file-location)
229    (%class :initarg :class :type sod-class :reader sod-slot-class)
230    (%type :initarg :type :type c-type :reader sod-slot-type))
231   (:documentation
232    "Slots are units of information storage in instances.
233
234    Each class defines a number of slots, which function similarly to (data)
235    members in structures.  An instance contains all of the slots defined in
236    its class and all of its superclasses.
237
238    A slot carries the following information.
239
240      * A `name', which distinguishes it from other slots defined by the same
241        class.  Unlike most (all?) other object systems, slots defined in
242        different classes are in distinct namespaces.  There are no special
243        restrictions on slot names.
244
245      * A `location', which states where in the user's source the slot was
246        defined.  This gets used in error messages.
247
248      * A `class', which states which class defined the slot.  The slot is
249        available in instances of this class and all of its descendents.
250
251      * A `type', which is the C type of the slot.  This must be an object
252        type (certainly not a function type, and it must be a complete type by
253        the time that the user header code has been scanned)."))
254
255 (defmethod print-object ((slot sod-slot) stream)
256   (maybe-print-unreadable-object (slot stream :type t)
257     (pprint-c-type (sod-slot-type slot) stream
258                    (format nil "~A.~A"
259                            (sod-class-nickname (sod-slot-class slot))
260                            (sod-slot-name slot)))))
261
262 (export '(sod-initializer sod-initializer-slot sod-initializer-class
263           sod-initializer-value))
264 (defclass sod-initializer ()
265   ((slot :initarg :slot :type sod-slot :reader sod-initializer-slot)
266    (location :initarg :location :initform (file-location nil)
267              :type file-location :reader file-location)
268    (%class :initarg :class :type sod-class :reader sod-initializer-class)
269    (value :initarg :value :type c-fragment :reader sod-initializer-value))
270   (:documentation
271    "Provides an initial value for a slot.
272
273    The slots of an initializer are as follows.
274
275      * The `slot' specifies which slot this initializer is meant to
276        initialize.
277
278      * The `location' states the position in the user's source file where the
279        initializer was found.  This gets used in error messages.  (Depending
280        on the source layout style, this might differ from the location in the
281        `value' C fragment.)
282
283      * The `class' states which class defined this initializer.  For instance
284        slot initializers (`sod-instance-initializer'), this will be the same
285        as the `slot''s class, or be one of its descendants.  For class slot
286        initializers (`sod-class-initializer'), this will be an instance of
287        the `slot''s class, or an instance of one of its descendants.
288
289      * The `value' gives the text of the initializer, as a C fragment.
290
291    Typically you'll see instances of subclasses of this class in the wild
292    rather than instances of this class directly.  See `sod-class-initializer'
293    and `sod-instance-initializer'."))
294
295 (defmethod print-object ((initializer sod-initializer) stream)
296   (with-slots (slot value) initializer
297     (if *print-escape*
298         (print-unreadable-object (initializer stream :type t)
299           (format stream "~A = ~A" slot value))
300         (format stream "~A" value))))
301
302 (export 'sod-class-initializer)
303 (defclass sod-class-initializer (sod-initializer)
304   ()
305   (:documentation
306    "Provides an initial value for a class slot.
307
308    A class slot initializer provides an initial value for a slot in the class
309    object (i.e., one of the slots defined by the class's metaclass).  Its
310    VALUE must have the syntax of an initializer, and its consituent
311    expressions must be constant expressions.
312
313    See `sod-initializer' for more details."))
314
315 (export 'sod-instance-initializer)
316 (defclass sod-instance-initializer (sod-initializer)
317   ()
318   (:documentation
319    "Provides an initial value for a slot in all instances.
320
321    An instance slot initializer provides an initial value for a slot in
322    instances of the class.  Its `value' must have the syntax of an
323    initializer.  Furthermore, if the slot has aggregate type, then you'd
324    better be sure that your compiler supports compound literals (6.5.2.5)
325    because that's what the initializer gets turned into.
326
327    See `sod-initializer' for more details."))
328
329 (export 'sod-initarg)
330 (defclass sod-initarg ()
331   ((%class :initarg :class :type sod-class :reader sod-initarg-class)
332    (location :initarg :location :initform (file-location nil)
333              :type file-location :reader file-location)
334    (name :initarg :name :type string :reader sod-initarg-name)
335    (%type :initarg :type :type c-type :reader sod-initarg-type))
336   (:documentation
337    "Describes a keyword argument accepted by the initialization function."))
338
339 (export 'sod-user-initarg)
340 (defclass sod-user-initarg (sod-initarg)
341   ((default :initarg :default :type t :reader sod-initarg-default))
342   (:documentation
343    "Describes an initialization argument defined by the user."))
344
345 (defmethod print-object ((initarg sod-user-initarg) stream)
346   (maybe-print-unreadable-object (initarg stream :type t)
347     (pprint-c-type (sod-initarg-type initarg) stream
348                    (sod-initarg-name initarg))
349     (awhen (sod-initarg-default initarg)
350       (format stream " = ~A" it))))
351
352 (export 'sod-slot-initarg)
353 (defclass sod-slot-initarg (sod-initarg)
354   ((slot :initarg :slot :type sod-slot :reader sod-initarg-slot))
355   (:documentation
356    "Describes an initialization argument used to initialize a slot."))
357
358 (defmethod print-object ((initarg sod-slot-initarg) stream)
359   (maybe-print-unreadable-object (initarg stream :type t)
360     (pprint-c-type (sod-initarg-type initarg) stream
361                    (sod-initarg-name initarg))
362     (format stream " for ~A" (sod-initarg-slot initarg))))
363
364 ;;;--------------------------------------------------------------------------
365 ;;; Messages and methods.
366
367 (export '(sod-message sod-message-name sod-message-class sod-message-type))
368 (defclass sod-message ()
369   ((name :initarg :name :type string :reader sod-message-name)
370    (location :initarg :location :initform (file-location nil)
371              :type file-location :reader file-location)
372    (%class :initarg :class :type sod-class :reader sod-message-class)
373    (%type :initarg :type :type c-function-type :reader sod-message-type))
374   (:documentation
375    "Messages are the means for stimulating an object to behave.
376
377    SOD is a single-dispatch object system, like Smalltalk, C++, Python and so
378    on, but unlike CLOS and Dylan.  Behaviour is invoked by `sending messages'
379    to objects.  A message carries a name (distinguishing it from other
380    messages recognized by the same class), and a number of arguments; the
381    object may return a value in response.  Sending a message therefore looks
382    very much like calling a function; indeed, each message bears the static
383    TYPE signature of a function.
384
385    An object reacts to being sent a message by executing an `effective
386    method', constructed from the direct methods defined on the recpient's
387    (run-time, not necessarily statically-declared) class and its superclasses
388    according to the message's `method combination'.
389
390    Much interesting work is done by subclasses of `sod-message', which (for
391    example) specify method combinations.
392
393    The slots are as follows.
394
395      * The `name' distinguishes the message from others defined by the same
396        class.  Unlike most (all?) other object systems, messages defined in
397        different classes are in distinct namespaces.  It is forbidden for a
398        message name to begin with an underscore, or to contain two
399        consecutive underscores.  (Final underscores are fine.)
400
401      * The `location' states where in the user's source the slot was defined.
402        It gets used in error messages.
403
404      * The `class' states which class defined the message.
405
406      * The `type' is a function type describing the message's arguments and
407        return type.
408
409    Subclasses can (and probably will) define additional slots."))
410
411 (defmethod print-object ((message sod-message) stream)
412   (maybe-print-unreadable-object (message stream :type t)
413     (pprint-c-type (sod-message-type message) stream
414                    (format nil "~A.~A"
415                            (sod-class-nickname (sod-message-class message))
416                            (sod-message-name message)))))
417
418 (export '(sod-method sod-method-message sod-method-class sod-method-type
419           sod-method-body))
420 (defclass sod-method ()
421   ((message :initarg :message :type sod-message :reader sod-method-message)
422    (location :initarg :location :initform (file-location nil)
423              :type file-location :reader file-location)
424    (%class :initarg :class :type sod-class :reader sod-method-class)
425    (%type :initarg :type :type c-function-type :reader sod-method-type)
426    (body :initarg :body :type (or c-fragment null) :reader sod-method-body))
427   (:documentation
428    "(Direct) methods are units of behaviour.
429
430    Methods are the unit of behaviour in SOD.  Classes define direct methods
431    for particular messages.
432
433    When a message is received by an instance, all of the methods defined for
434    that message on that instance's (run-time, not static) class and its
435    superclasses are `applicable'.  The applicable methods are gathered
436    together and invoked in some way; the details of this are left to the
437    `method combination', determined by the subclass of `sod-message'.
438
439    The slots are as follows.
440
441      * The `message' describes which meessage invokes the method's behaviour.
442        The method is combined with other methods on the same message
443        according to the message's method combination, to form an `effective
444        method'.
445
446      * The `location' states where, in the user's source, the method was
447        defined.  This gets used in error messages.  (Depending on the user's
448        coding style, this location might be subtly different from the
449        `body''s location.)
450
451      * The `class' specifies which class defined the method.  This will be
452        either the class of the message, or one of its descendents.
453
454      * The `type' gives the type of the method, including its arguments.
455        This will, in general, differ from the type of the message for several
456        reasons.
457
458          -- The method type must include names for all of the method's
459             parameters.  The message definition can omit the parameter
460             names (in the same way as a function declaration can).  Formally,
461             the message definition can contain abstract declarators, whereas
462             method definitions must not.
463
464          -- Method combinations may require different parameter or return
465             types.  For example, `before' and `after' methods don't
466             contribute to the message's return value, so they must be defined
467             as returning `void'.
468
469          -- Method combinations may permit methods whose parameter and/or
470             return types don't exactly match the corresponding types of the
471             message.  For example, one might have methods with covariant
472             return types and contravariant parameter types.  (This sounds
473             nice, but it doesn't actually seem like such a clever idea when
474             you consider that the co-/contravariance must hold among all the
475             applicable methods ordered according to the class precedence
476             list.  As a result, a user might have to work hard to build
477             subclasses whose CPLs match the restrictions implied by the
478             method types.)
479
480    Method objects are fairly passive in the SOD translator.  However,
481    subclasses of `sod-message' may (and probably will) construct instances of
482    subclasses of `sod-method' in order to carry the additional metadata they
483    need to keep track of."))
484
485 (defmethod print-object ((method sod-method) stream)
486   (maybe-print-unreadable-object (method stream :type t)
487     (format stream "~A ~@_~A"
488             (sod-method-message method)
489             (sod-method-class method))))
490
491 ;;;----- That's all, folks --------------------------------------------------