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