source: project/wiki/eggref/4/operations @ 14680

Last change on this file since 14680 was 14680, checked in by felix winkelmann, 11 years ago

copied

File size: 10.6 KB
Line 
1[[toc:]]
2[[tags: eggs]]
3
4== operations
5
6This extension implements the T object system.
7
8This library supports the object-oriented style with a special kind of procedure
9known as an ''operation'', and with forms which permit one to create
10objects which exhibit certain behavior when a given operation is applied
11to them.
12
13When an operation is called, the following sequence of events occurs:
14
15* A ''handler'' is obtained for the object which was the operation's first argument.  (Operations must always be called with at least one argument.)
16
17* The operation asks the handler for a ''method'' which will handle the operation for the object.
18
19* The handler either provides a method, or it indicates that the object is not prepared to handle the operation.
20
21* If the handler provided a method, the method is invoked. If not, then the operation's \iix{default method}, if any, is invoked. If the operation has no default method, then the effect of the call to the operation is undefined (and presumably an error condition is signalled).
22
23In this way, an object's handler may determine how the operation
24is to be performed for the object - that is, which particular method
25is to be invoked as a result of invoking the operation.
26
27Handlers map operations to methods.  Many objects may have the same
28handler, or a handler may be idiosyncratic to a particular object.
29However, every object has a handler, so all objects participate in the
30generic operation dispatch protocol.
31
32This extension supports static linking
33
34=== Fundamental forms
35
36The basis of the generic operation system consists of the two special
37forms {{OBJECT}} and {{OPERATION}}.  {{OBJECT}}-expressions create
38objects which respond appropriately to generic operations, and
39{{OPERATION}}-expressions evaluate to operations.
40
41  [syntax] (object procedure} . method-clauses) -->  object
42
43An {{OBJECT}}-expression yields an object which is prepared to handle
44generic operations according to the ''method-clauses''.
45In the following description, ``the object'' refers
46to the value of a given {{OBJECT}}-expression.
47
48Each ''method-clause'' should be of the form
49
50  ((operation . variables) . body)
51
52''Operation'' is an evaluated position, and is typically a variable
53which evaluates to an operation, although it may be any
54expression.  When an operation is called with the object as its first
55argument, the ''operation''-expressions are evaluated,
56and if one yields the operation being applied to the object, the corresponding
57''method-clause'' is selected.  The operation is then performed
58according to the selected ''method-clause'': the clause's ''variables''
59are bound to the arguments to the operation,
60and its ''body'', an implicit block, is evaluated.
61
62  (define op (operation #f))
63  (op (object #f ((op self) 34)))      ==> 34
64  (op (object #f ((op self x) x)) 55)  ==> 55
65
66''Procedure'' may be any expression, and is evaluated at the time the
67{{OBJECT}}-expression is evaluated.  The object, when called, simply
68calls the value of the ''procedure'' expression, passing on any
69arguments.  Typically ''procedure'' might be either a
70{{LAMBDA}}-expression, if the object is to be callable, or it is
71{{#f}}, which by convention means that the object is not intended to
72be called, the value of {{#f}} being an uncallable object.
73
74In the degenerate case, where there are no method clauses, the value of
75
76  (object (lambda args . body))
77
78is indistinguishable from that of
79
80  (lambda args . body)
81
82The semantics of the {{OBJECT}} and {{OPERATION}} special forms
83can be described in terms of hypothetical primitive procedures
84{{*OBJECT}} and {{GET-HANDLER}}.
85These primitives do not actually
86exist, but are introduced here as expository aids.
87{{*OBJECT}} takes two arguments, and returns an object which, when
88called, calls the object which was {{*OBJECT}}'s first argument, and
89when given to {{GET-HANDLER}} returns the object which was
90{{*OBJECT}}'s second argument.  That is,
91{{*OBJECT}} creates a two-component record (like a pair),
92{{GET-HANDLER}} extracts one component, and the other component is
93called when the record is called.
94
95  (get-handler (*object proc handler))   ==>  handler
96  ((*object proc handler) arg ...)       ==>  (proc arg ...)
97
98In addition, {{GET-HANDLER}} is defined on ''all'' objects to return
99some handler, even objects not created by {{*OBJECT}} (if indeed
100there are any such objects).
101
102Given these primitives, the following rough equivalence holds:
103
104  (object proc
105        ((op1 . args1) . body1)
106        ((op2 . args2) . body2)
107        ...
108        ((opn . argsn) . bodyn))
109  ==>
110  (*object proc
111         (lambda (op)
112           (switch op
113             (op1 (lambda args1 . body1))
114             (op2 (lambda args2 . body2))
115             ...
116             (opn (lambda argsn . bodyn))
117             (else #f))))
118
119The outer {{LAMBDA}}-expression yields the object's handler;
120the inner {{LAMBDA}}-expressions yield the methods, and
121the mapping from operations to methods is accomplished by
122the {{SWITCH}}-expression
123Note that the syntactic positions
124
125  op1,
126  op2,
127  ...
128  opN
129
130are evaluated positions, and the operation expressions
131are evaluated when an operation is applied to the object,
132not when the object is created.
133
134  [syntax] (operation default . method-clauses)   --> operation
135
136The syntax of {{OPERATION}} is the same as that of {{OBJECT}}, but its
137semantics and application are somewhat different.  An
138{{OPERATION}}-expression evaluates to an operation.  When called, the
139operation obtains a handler for its first argument, calls the handler to
140obtain a method, and then invokes the method.  The default method for
141the operation is established as being ''default''.
142
143As the subject of another generic operation, an operation is an object
144like any other, and in this case the operation acts just as if it had
145been created by an {{OBJECT}}-expression with the same ''method-clauses''.
146In this way one can establish the behavior of an operation
147when subject to other operations, for example {{SETTER}}.
148
149The following rough equivalence describes the semantics of {{OPERATION}}.
150Some details have been omitted.
151
152  (operation default . methods)
153   ==>
154  (labels ((op (object (lambda (obj . args)
155                       (let ((method ((get-handler obj) op)))
156                         (cond (method
157                                (apply method obj args))
158                               (else
159                                (apply default obj args)))))
160                     . methods)))
161  op)
162
163For example:
164
165  (define op (operation (lambda (obj) 'zebu)))
166  (op (object #f ((op self) 'quagga)))    -->  quagga
167  (op 'eland)                              -->  zebu
168
169An operation is created, and the variable {{OP}} is bound to it.
170The operation's default method always returns the symbol {{ZEBU}}.
171When the operation is applied to the value of the {{OBJECT}}-expression,
172the appropriate method is invoked, and the call to the operation yields
173the symbol {{QUAGGA}}.  When the operation is applied to an object
174which doesn't handle it - the symbol {{ELAND}} - the operation's
175default method is invoked, so the call yields the symbol {{ZEBU}}.
176
177  [procedure] (operation? object)  -->  boolean
178
179Returns true if ''object'' is an operation.
180
181
182=== Defining operations
183
184  [syntax] (define-operation (variable . argument-vars) . body)   -->  undefined
185
186Defines ''variable'' to be an operation.
187The syntax is intended to be analogous to that of {{DEFINE}}.
188The operation's default method is defined by ''argument-vars'' and ''body''.
189If there is no ''body'', then the operation's default method
190is undefined.  In this case, the ''argument-vars''
191appear only for documentary purposes.
192
193  (define-operation (var . args) . body)
194    ==> (define var (operation (lambda args . body)))
195
196  (define-operation (var . args))
197    ==> (define var (operation undefined-effect))
198
199  [syntax] (define-settable-operation (variable . argument-vars) . body)   --> undefined
200
201Defines ''variable'' to be an operation, as with {{DEFINE-OPERATION}},
202but arranges for the operation's ``setter'' to be another operation,
203so that the operation is ``settable''
204
205  (define-settable-operation (var . args) . body)
206    ==>
207  (define var
208  (let ((the-setter (operation undefined-effect)))
209    (operation (lambda args . body)
210      ((setter self) the-setter))))
211
212  [syntax] (define-predicate variable)  -->  undefined
213
214Defines ''variable'' to be an operation which, by default,
215returns false.
216
217  (define-predicate var)
218    ==>
219  (define-operation (var obj) #f)
220
221The intent is that particular {{OBJECT}}-expressions contain clauses
222of the form {{((variable SELF) #t)}}.  This way the operation
223defined by {{DEFINE-PREDICATE}} may act as a type predicate that returns
224true only for those objects returned by such {{OBJECT}}-expressions.
225
226
227=== Example
228
229Hypothetical implementation of {{cons}}:
230
231  (define-predicate pair?)
232  (define-settable-operation (car pair))
233  (define-settable-operation (cdr pair))
234
235  (define (cons the-car the-cdr)
236    (object #f
237          ((pair? self) #t)
238          ((car self) the-car)
239          ((cdr self) the-cdr)
240          (((setter car) self new-car) (set the-car new-car))
241          (((setter cdr) self new-cdr) (set the-cdr new-cdr))))
242
243== Author
244
245[[/users/felix winkelmann|felix winkelmann]]
246
247== License
248
249 Copyright (c) 2007, Felix L. Winkelmann
250 All rights reserved.
251
252 Redistribution and use in source and binary forms, with or without
253 modification, are permitted provided that the following conditions are met:
254 
255   Redistributions of source code must retain the above copyright notice,
256     this list of conditions and the following disclaimer.
257   Redistributions in binary form must reproduce the above copyright notice,
258     this list of conditions and the following disclaimer in the
259     documentation and/or other materials provided with the distribution.
260   Neither the name of the author nor the names of its contributors may be
261     used to endorse or promote products derived from this software without
262     specific prior written permission.
263 
264 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
265 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
266 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
267 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
268 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
269 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
270 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
271 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
273 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
274 POSSIBILITY OF SUCH DAMAGE.
275
276== Version History
277
278; 0.1 : Initial release
Note: See TracBrowser for help on using the repository browser.