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

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

updated operations wiki page

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