-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsrfi-20.html
364 lines (330 loc) · 15.3 KB
/
srfi-20.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>SRFI 20: Simple object system </title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/srfi.css" type="text/css" />
</head>
<body>
<H1>Title</H1>
Simple object system.
<H1>Author</H1>
Christian Queinnec
<H1>Status</H1>
<p>This SRFI is currently in <em>withdrawn</em> status. Here is <a href="https://srfi.schemers.org/srfi-process.html">an explanation</a> of each status that a SRFI can hold. To provide input on this SRFI, please send email to <code><a href="mailto:srfi+minus+20 +at+srfi+dotschemers+dot+org">srfi-20 @<span class="antispam">nospam</span>srfi.schemers.org</a></code>. To subscribe to the list, follow <a href="https://srfi.schemers.org/srfi-list-subscribe.html">these instructions</a>. You can access previous messages via the mailing list <a href="https://srfi-email.schemers.org/srfi-20 ">archive</a>.</p>
<UL>
<LI>Draft: 2000-04-16--2000-06-15 </LI>
<LI>Withdrawn: 2001-04-29
<LI>Revised to fix errata:
<ul><li>2019-10-25 (Fix broken links.)</LI></UL></LI>
</UL>
<H1>Abstract</H1>
This SRFI presents an object system to define classes, generic functions
as well as to support some level of introspection. This object system
is based on Meroon-V3 which is itself inspired by CLOS. <a
href="http://pages.lip6.fr/Christian.Queinnec/WWW/Meroon.html">Meroon-V3</a>
is distributed and used since 1992.
<H1>Issues</H1>
There are two kinds of object models: the closed model or the open
model. The closed model comes from statically typed systems (C++,
Java, OCaml, etc.); this model is characterized by the following
dogmas: classes are encapsulation units, methods must be known at
class-definition time, there's only one receiver for a message (since
generic functions are hard to type). This model has good compilation
properties since most types are known at compile-time.
<p>
The open model is more dynamic (CLOS, <a
href="http://pages.lip6.fr/Christian.Queinnec/WWW/Meroon.html">
Meroon-V3</a>, <a href="http://kaolin.unice.fr/STk/"> STklos</a>). It
acknowledges the fact that all behaviors cannot be expressed at
class-definition time, that it should be possible to add new behaviors
to existing instances (data, particularly if persistent, often
pre-exist to treatments), that introspection is desirable and useful
for serialization, debug and all sorts of walkers, that some way to
customize or extend the implementation should also exist as well.
<p>
This document proposes an open model in the dynamic spirit of Scheme
(and Lisp). Meta-object aspects are not considered in this proposal
but are still possible.
<H1>Rationale</H1>
Objects are useful and trendy (at least before components
come). Meroon-V3 has proved useful for many years, has been ported to
(no particular order intended) mzscheme, scheme->C, elk, bigloo, scm,
guile, oscheme, mit-scheme, gambit. It is proposed to build on its
strengths.
<p>
This model makes possible that vectors be regular instances of the
object system since the object system allows fields to be regular (ie
Mono-Field (a Mono-Field only holds one value)) or indexed (ie
Poly-Field, the number of values it may hold is fixed at
instantiation-time). Vectors are regular objects
with a single indexed field.
<p>
The proposed model is based on simple inheritance (for the same reasons
Java took).
<H1>Specification</H1>
The <a href="https://pages.lip6.fr/Christian.Queinnec/Reports/MeroonV3.ps.gz">
documentation of Meroon-V3</a> (23 pages) is available on the net.
The following interface stresses the features that are within the
scope of the present document.
<p>
The following are new special-forms. They use keywords ie symbols
prefixed with a colon.
<pre>
(define-class class-name superclass-name
(field-specification ...)
;; where field-specification is
;; ([ = | * ] field-name
;; [ :mutable | :immutable |
;; :initialize (lambda () form) | ; for (=) Mono-Field
;; :initialize (lambda (index) form) ; for (*) Poly-Field
;; ] )
[ :prototype ] ) ; non-instantiable class
(define-generic (generic-name variable ...)
;; where variable is
;; symbol ; regular variable
;; | (symbol [ class-name ]) ; discriminating variable
[ default-body ] )
(define-method (generic-name variable ...)
;; where variable is
;; symbol ; regular variable
;; | (symbol class-name) ; discriminating variable
body ; (call-next-method) allowed
)
(instantiate class-name
:mono-field-name form
:poly-field-name form ...
:poly-field-length size
... ) </pre>
<h2> Class definition </h2>
<p>
A <tt>define-class</tt> form creates a new class (redefinition of
classes is left unspecified). The first parameter is the name of the
class, the second is the name of the super-class, specifications of
fields appear as third parameter, additional parameters may appear
after. Except initializers that are evaluated, no parameter or
expressions within parameters are evaluated.
<p>
A class is made of fields which may be regular or indexed. A
field may be mutable or not (mutable by default). A default
initializer may be specified (a thunk for a regular field, a unary
function for an indexed field). The form that define these
initializers are evaluated at class-definition time. The
<tt>:prototype</tt> class option forbids instantiation of the class.
<p>
When a class is defined, some functions are created: a predicate and
some read/write accessors.
<h3> Example </h3>
<p>
The following class definition creates the
following functions: <tt>Foo?</tt>, <tt>Foo-bar</tt>,
<tt>Foo-hux</tt>, <tt>set-Foo-hux!</tt> and <tt>Foo-hux-length</tt>. A
variable <tt>Foo-class</tt> is also created that holds a (possibly
indirect) instance of <tt>Class</tt> for introspection purpose.
<pre>
(define-class Foo Object
((= bar :immutable)
(* hux :initializer (lambda (i) i)) ) )
</pre>
<p>
Here is the signature of the generated functions: <pre>
(Foo? anySchemeValue) -> boolean
(Foo-bar aFooInstance) -> anySchemeValue
(Foo-hux aFooInstance aNaturalNumber) -> anySchemeValue
(set-Foo-hux! aFooInstance anySchemeValue aNaturalNumber) -> unspecified
(Foo-hux-length aFooInstance) -> aNaturalNumber
</pre>
<p>
Predicates, such as <tt>Foo?</tt> may be invoked on any Scheme values.
Accessors may only apply on (possibly indirect) instances of <tt>Foo</tt>.
Writers return an unspecified value. Accessors whether readers or writers
when applied on an indexed field take an index as last argument.
<h2> Generic definition </h2>
<p>
The <tt>define-generic</tt> form defines generic functions. When a
generic function is defined, it does not possess any method. However
it may have a default body which is invoked when no specific method is
found (for instance, on values that are not objects). The generic
function must specify the discriminating variables (at least
one). Syntactically a discriminating variable appears within
parentheses. If a class is associated to a discriminating variable,
it restricts the set of methods that may be adjoined to this generic
function (for instance, the following <tt>clone</tt> function may only
have methods defined on subclasses of <tt>Object</tt>). A generic
function may have more than one discriminating variable.
<p>
The following are predefined generic functions. New methods may be
added at will by programmers.
<pre>
(define-generic (initialize! (o Object)) ...)
(define-generic (clone (o Object)) ...)
</pre>
<p>
The <tt>initialize!</tt> function is automatically invoked on every
freshly created instance. It may be used to register the instance in
some data structures.
<p>
The <tt>clone</tt> function, by default, performs a shallow copy of an
object.
<h3> Example </h3>
<p>
A generic predicate <tt>werk?</tt> may be defined on all (direct or
indirect) instances of <tt>Object</tt> as:
<pre>
(define-generic (werk? (o))
#f )
</pre>
<h2> Method definition</h2>
<p>
The <tt>define-method</tt> form adjoins a method to a generic functions.
Methods may be adjoined to any generic functions provided that the
method has a compatible signature ie the same number of discriminating
variables at the same position associated to classes that are
sub-classes of the classes mentioned in the generic function
definition. If the generic function has a final dotted variable, then
methods should also have such a final dotted variable.
<p>
Within the body of a method, it is possible to use the
<tt>(call-next-method)</tt> local special form. It is not possible to
use it elsewhere. The next method is defined to be the method that
would have been invoked if the current method was absent. It is
forbidden to define ambiguous multi-method that is a method that will
make some signature ambiguous. This problem may only arise on methods
that have strictly more than one discriminating variable: is SC is a
subclass of C and a method M1 is defined on SC * C then it is not
possible to define a method M2 on C * SC since that would make a call
on SC * SC ambiguous. However if a method M3 on SC * SC is defined and
does not contain a call to <tt>(call-next-method)</tt> then it is then
possible to define a method M2 on C * SC. [NOTE: that may be
considered as too dynamic, observe however that
<tt>call-next-method</tt> is not a variable.]
<h3> Example </h3>
<p>
If all (direct or indirect) instances of <tt>Foo</tt> satisfy the
<tt>werk?</tt> predicate, then one may write:
<pre>
(define-method (werk? (o Foo))
#t )
</pre>
<h2> Instantiation </h2>
<p>
New objects may be created with the <tt>instantiate</tt> special form.
This form takes as first parameter the name of a class. The other
parameters specify the initial content of the object. The initial
content of a field is specified by a keyword whose name is the name of
the field to fill (prefixed with a colon). If the field is regular,
the keyword is followed by a single expression (to be evaluated); if
the field is indexed, the keyword is followed by as many expressions
(to be evaluated) as needed. Alternatively, an indexed field may be
specified by its length in which case the initial content of this
indexed field is unspecified.
<p>
The fields do not need to be ordered nor to be all specified. In which
case, the initializer if defined at class-definition-time is run. For
a regular field, the initializer looks like a thunk; for an indexed
field, the initializer is a unary function taking the index as
argument. Fields are guaranteed to be filled in order starting from
inherited fields. Indexed fields are filled starting from 0.
<h3> Example </h3>
<p>
Here are some instantiations of <tt>Foo</tt>:
<pre>
(instantiate Foo :bar 1 :hux 2 3 4)
(instantiate Foo :hux-length 3 :bar 11)
</pre>
Note that the values of the fields may be given in any order. A
mono-field defined with an initializer may be omitted. A poly-field
defined with an initializer only requires its length to be given.
<h2> Primitives </h2>
<p>
The following are regular functions. Note: <tt>value</tt> means whatever
Scheme value; <tt>object</tt> means a (possibly indirect) instance of
<tt>Object</tt>; <tt>class</tt> means a (possibly indirect) instance of
<tt>Class</tt>.
<pre>
(object? value) ; anySchemeValue -> boolean
(object->class object) ; Object -> Class
(is-a? value class) ; anySchemeValue * Class -> boolean
(subclass? class super-class) ; Class * Class -> boolean
</pre>
<p>
Among meta-objects only classes and fields are partially exposed not
by their definition but through some functions or some variables.
<tt>Class</tt> is the ``class of classes'' where classes are the
values returned by the <tt>object->class</tt> function. The document
does not impose <tt>Class</tt> to be definable by a specific
<tt>define-class</tt> form. Classes may only be used with the
functions whose name start with <tt>Class-</tt>.
<p>
<tt>Field</tt> is the class of fields, objects reifying information
about fields. The document does not impose <tt>Field</tt> to be
definable by a specific <tt>define-class</tt> form. Fields may only be
used with the functions whose name start with <tt>Field-</tt>.
<p>
The definition of a class may be inspected via a number of functions.
It is possible to access the name of a class, its superclass
(<tt>#f</tt> if that does not exist) as well as its fields. Fields are
reified as if instances of a class of fields: <tt>Field</tt>. The
document does not impose <tt>Field</tt> to exist (as if explicitly
created by <tt>define-class</tt>) provided the <tt>Field-</tt>*
functions still exist.
<pre>
Object-class ; Class
(Class? value) ; anySchemeValue -> boolean
(Class-name class) ; Class -> symbol
(Class-super-class class) ; Class -> Class
(Class-field class index) ; Class * nat -> Field
(Field? value) ; anySchemeValue -> boolean
(Field-name field) ; Field -> symbol
(Field-mutable? field) ; Field -> boolean
(Field-initializer field) ; Field -> closure
(Mono-Field? value) ; anySchemeValue -> boolean
(Poly-Field? value) ; anySchemeValue -> boolean
(field-value object field [ index ]) ; Object * Field [* nat] -> value
(set-field-value! object value field [ index ]) ; Object * value * Field [* nat] -> unspecified
(field-length object field) ; Object * Field -> nat
</pre>
<p>
Two generic functions are predefined:
<pre>
(initialize! object) ; Object -> Object
(clone object) ; Object -> Object
</pre>
<H1>Implementation</H1>
<A HREF="https://pages.lip6.fr/Christian.Queinnec/Programs/MeroonV3-98Feb09.tar.gz">
Meroon-V3</a> implements the features of this document (and much more
than this in fact) but is currently 10k lines long. <A
HREF="https://pages.lip6.fr/Christian.Queinnec/Programs/meroonet93Mar19.tar.gz">
Meroonet</a> is another almost conforming essential implementation
(but for multi-methods) whose size makes it more readable (875 lines
including comments) described in chapter 11 of my book: Lisp in Small
Pieces, Cambridge U. Press, 1996.
<H1>Copyright</H1>
<p>Copyright (C) Christian Queinnec (2000). All Rights Reserved.</p>
<p>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
</p>
<p>
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</p>
<HR>
<ADDRESS>Editor: <A href="mailto:srfi minus editors at srfi dot schemers dot org">Mike Sperber</A></ADDRESS>
</BODY>
</HTML>