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 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
|
.so ../util/tmac.scheme
.Ul
.TL
The \s-1OOPS\s0 Package for Elk Scheme
.AU
Oliver Laumann
.
.Ch "Introduction"
.
.PP
The \s-1OOPS\s0 package provides a minimal set of tools that enables
a Scheme programmer to program in an object oriented style.
The functionality of \s-1OOPS\s0 is similar to that of packages like
\s-1CLOS\s0 and \s-1SCOOPS\s0, although the current version does
not support multiple inheritance.
The rest of this memo serves as a reference guide to the
\s-1OOPS\s0 package; the reader is assumed to be familiar with
the terminology of object oriented programming.
.
.Ch "Using \s-1OOPS\s0"
.LP
Programs that make use of the \s-1OOPS\s0 package should include
the line
.Ss
(require 'oops)
.Se
.Ix oops
Since this involves autoloading of an object file, it may be desirable
to dump Scheme after the \s-1OOPS\s0 package has been loaded.
.
.Ch "Defining Classes"
.PP
New classes are defined by means of the
.S define-class
.Id define-class
macro.
The syntax of
.S define-class
is
.Ss
(define-class \f2class-name\fP . \f2options\fP)
.Se
where \f2class-name\fP is a symbol.
\f2options\fP can be of the form
.Ss
(super-class \f2class-name\fP)
.Se
.Id super-class
where \f2class-name\fP is the name of the super-class (a symbol),
or
.Ss
(class-vars . \f2var-specs\fP)
.Se
.Id class-vars
or
.Ss
(instance-vars . \f2var-specs\fP)
.Se
.Id instance-vars
to specify the class variables
.Ix "class variables"
and instance variables
.Ix "instance variables"
of the newly defined class.
Each \f2var-spec\fP is either a symbol (the name of the variable)
or of the form
.Ss
(\f2symbol\fP \f2initializer\fP).
.Se
Variables for which no initializer has been specified are initialized
to the empty list.
The initializers
.Ix initializers
for class variables are evaluated immediately;
initializers for instance variables are evaluated each time an
instance of the newly defined class is created.
Evaluation of initializers is performed in a way that the
initializer of a variable can reference all variables appearing
at the left of the variable being initialized; for instance
.Ss
(define-class foo (class-vars (a 10) (b (* a 2))))
.Se
would initialize the class variable
.S b
to 20.
.PP
A class inherits all class variables, instance variables, and
methods of its super-class.
When a class and its super-class each have an instance variable
with the same name, the corresponding \f2var-specs\fP must either
both have no initializer or initializers with the same value,
otherwise an ``initializer mismatch'' error is signaled by
.S define-class .
.PP
Each instance of a class has an instance variable named
.S self .
.Id self
The value of
.S self
is the instance with respect to which
.S self
is evaluated.
.S self
can be used by methods as the argument to
.S send
.Ix send
(see below) to invoke another method within the current instance.
.PP
.S define-class
does not have a meaningful return value,
instead it has a side-effect on the environment in which it
is invoked.
.
.Ch "Creating Instances of a Class"
.PP
The macro
.S make-instance
.Id make-instance
is used to create an instance of
a class; it returns the instance as its value.
The syntax is
.Ss
(make-instance \f2class\fP . \f2args\fP)
.Se
where \f2class\fP is the class of which an instance is to
be created.
Each \f2arg\fP of the form
.Ss
(\f2symbol\fP\ \f2initializer\fP)
.Se
where \f2symbol\fP is the name of an instance variable of the class,
is used to initialize the specified instance variable in the
newly created instance.
In this case the \f2initializer\fP supersedes any initializer
specified in the call to
.S define-class .
Thus it is possible to have instance variables with a \f2default
initializer\fP that can be overridden for individual instances.
The initializers are evaluated in the current environment.
.PP
.S make-instance
initializes the newly created instance by
invoking the
.S initialize-instance
.Id initialize-instance
method for the class
and all super-classes in super-class to sub-class order.
That is, the
.S initialize-instance
method of the class specified in the call to
.S make-instance
is called after all other
.S initialize-instance
methods.
The arguments passed to the
.S initialize-instance
method of a class are those arguments of the call to
.S make-instance
that do not represent an initialization form for an instance variable.
These arguments are evaluated in the current environment.
It is not required for a class to have an
.S initialize-instance
method.
.PP
Consider the following example:
.Ss
(require 'oops)
.sp .5
(define-class c (instance-vars a))
(define-class d (instance-vars (b 10)) (super-class c))
.sp .5
(define-method c (initialize-instance . args)
(print (cons 'c args)))
.sp .5
(define-method d (initialize-instance . args)
(print (cons 'd args)))
.sp .5
.Se
In this example evaluation of
.Ss
(define x 99)
(define i (make-instance d (a 20) 'foo (b x) x))
.Se
would print
.Ss
(c foo 99)
(d foo 99)
.Se
.PP
Note that first the
.S initialize-instance
method of
.S c
is invoked and then that of the class
.S d .
The instance variables
.S a
and
.S b
would be initialized to 20 and 99, respectively.
.
.Ch "Defining Methods"
.PP
A new method can be defined by means of the
.S define-method
.Id define-method
macro.
The syntax is
.Ss
(define-method \f2class\fP \f2lambda-list\fP . \f2body\fP)
.Se
where \f2class\fP is the class to which the method is to be
added, \f2lambda-list\fP is a list specifying the method's
name and formal arguments (having the same syntax as the argument
of
.S define ).
.PP
.S define-method
simply creates a class-variable with the name
of the method, creates a lambda closure using the \f2lambda-list\fP
and the \f2body\fP forms, and binds the resulting procedure to
the newly-created variable.
When a message with the name of the method is sent to an instance
of the class, the method is invoked, and the \f2body\fP is evaluated
in the scope of the instance (so that it can access all instance
and class variables).
.
.Ch "Sending Messages"
.PP
A message can be sent to an instance by means of the function
.S send .
.Id send
The syntax of
.S send
is
.Ss
(send \f2instance\fP \f2message\fP . \f2args\fP)
.Se
where \f2instance\fP is the instance to which the message is
to be sent, \f2message\fP is the name of the method to be
invoked (a symbol), and \f2args\fP are the arguments to be
passed to the method.
Example:
.Ss
(define-class c (instance-vars a) (class-vars (b 10)))
.sp .5
(define-method c (foo x)
(cons (set! a x) b)) ; set! returns previous value
.sp .5
(define i (make-instance c (a 99)))
.sp
(send i 'foo 1) \f1returns (99 . 10)\fP
(send i 'foo 2) \f1returns (1 . 10)\fP
.Se
.PP
When a message is sent to an instance for which no method has
been defined, a ``message not understood'' error is signaled.
.PP
The function
.S send-if-handles
.Id send-if-handles
is identical to
.S send ,
except that it returns a list of one element, the return value
of the method, or
.S #f
when the message is not understood by the instance.
.
.Ch "Evaluating Expressions within an Instance"
.PP
The macro
.S with-instance
.Id with-instance
can be used to evaluate expressions within the scope of an instance.
The syntax is
.Ss
(with-instance \f2instance\fP . \f2body\fP).
.Se
The \f2body\fP forms are evaluated in the same environment in
which a method of \f2instance\fP would be evaluated,
i.\|e. they can access all and class and instance variables
(including
.S self ).
.S with-instance
returns the value of the last \f2body\fP form.
Example:
.Ss
(define-class c (class-vars (x 5)) (instance-vars y))
.sp .5
(define i (make-instance c (y 1)))
.sp .5
(define x 10)
(with-instance i (cons x y)) \f1returns (5 . 1)\fP
.Se
.
.Ch "Setting Instance and Class Variables"
.PP
Generally class and instance variables are manipulated by methods
or, if applicable, from within a
.S with-instance
form.
In addition, values can be assigned to class and instance variables
without involving a message send by means of the
.S instance-set!
.Id instance-set!
macro.
The syntax of
.S instance-set!
is
.Ss
(instance-set! \f2instance\fP \f2variable\fP \f2value\fP)
.Se
where \f2variable\fP is a symbol, the name of the class or
instance variable.
.S instance-set!
returns the previous value of the variable (like
.S set! ).
.PP
Class variables can be modified without involving an instance
of the class by means of the macro
.S class-set! :
.Id class-set!
.Ss
(class-set! \f2class\fP \f2variable\fP \f2value\fP).
.Se
\f2variable\fP must be the name of a class variable of \f2class\fP.
Note that one difference between
.Ss
(instance-set! i 'var x)
.Se
and
.Ss
(with-instance i (set! var x))
.Se
is that in the former case
.S x
is evaluated in the current environment while in the latter case
.S x
is evaluated within the scope of the instance (here
.S x
might be a class or instance variable).
.
.Ch "Obtaining Information about Classes and Instances"
.PP
The function
.S class-name
.Id class-name
returns the name of a class (a symbol) or, when applied to an instance,
the name of the class of which it is an instance.
.PP
The predicate
.S method-known?
.Id method-known?
can be used to check whether a method of a given name is known to a class.
The syntax is
.Ss
(method-known? \f2method\fP \f2class\fP)
.Se
where \f2method\fP is a symbol.
.PP
The type predicates
.S class?
.Id class?
and
.S instance?
.Id instance?
can be used to check whether an object is a class or an instance,
respectively.
.PP
The functions
.Ss
(check-class \f2symbol\fP \f2object\fP)
.Se
.Id check-class
and
.Ss
(check-instance \f2symbol\fP \f2object\fP)
.Se
.Id check-instance
check whether \f2object\fP is a class (i.\|e. satisfies the predicate
.S class? )
or an instance, respectively, and, if not, signal an error;
in this case \f2symbol\fP is used as the first argument to
.S error .
.PP
The functions
.S describe-class
.Id describe-class
and
.S describe-instance
.Id describe-instance
print the components (name, class/instance variables, etc.) of
a class or instance, respectively.
The function
.S describe
.Id describe
has been extended in way that when
.S "(feature? 'oops)"
is true,
.S describe-class
or
.S describe-instance
are called when
.S describe
is applied to an object that satisfies
.S class?
or
.S instance? ,
respectively.
|