SCOOPS - the Scheme Object-Oriented Programming System Documentation for the version for MIT Scheme 7.1 -----------------------------------------------Notes originally by Steve Sherin; revamped by Peter Ross, Dept of AI, University of Edinburgh, 6 May 1991. SCOOPS is copyright Texas Instruments; the following copyright notice appears in the software: ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; ;;; Copyright (c) 1986 Texas Instruments Incorporated Permission to copy this software, to redistribute it, and to use it for any purpose is granted, subject to the following restrictions and understandings. 1. Any copy made of this software must include this copyright notice in full. 2. All materials developed as a consequence of the use of this software shall duly acknowledge such use, in accordance with the usual standards of acknowledging credit in academic research. 3. TI has made no warranty or representation that the operation of this software will be error-free, and TI is under no obligation to provide any services, by way of maintenance, update, or otherwise. 4. In conjunction with products arising from the use of this material, there shall be no use of the name of Texas Instruments (except for the above copyright credit) nor of any adaptation thereof in any advertising, promotional, or sales literature without prior written consent from TI in each case. Getting started --------------You may have to find the file scoops.scm which contains the full source. You can load it to get an interpreted version; there may be one or both of scoops.bin and scoops.com in the same directory. To load, just do (load "<WHEREVER>/scoops") and the loader will find the fastest-running version of the three loadable forms. If you can only find scoops.scm, you can compile it. First start up Scheme with the compiler, by the UN*X command % scheme -compiler which typically takes a short while. Then, to compile scoops, execute (cf "scoops.scm") which will create both scoops.bin and scoops.com, but don't hold your breath, go for a coffee instead. Afterwards, just load the system with (load "scoops") although you may prefer to restart Scheme without the compiler `band', in order to save space, before loading SCOOPS. Introduction -----------SCOOPS is an object-oriented system written in Scheme. It offers multiple rather than single inheritance, class variables as well as instance variables, run-time addition and deletion of methods, active values, and selectively settable/gettable/inittable instance variables. There is no support for method combination, either by send-super or by before/after daemons. If all this means nothing to you, it's time to go and read up about object-oriented programming; this is not a primer. The inheritance strategy used is pure depth-first, omitting any classes already visited in the search; this is different from the `up-to-thejoins' strategy used in some other object-oriented systems such as Flavors and Loops. Note that classes are defined in a global context. The following section summarises the functions which comprise the user level of the SCOOPS system. Functions: ---------DEFINE-CLASS (define-class <name> (mixins <parent-classes>) ; optional (classvars <binding-pairs or names for default value>) ; optional (instvars " " " ) ; optional (options <set-spec> <get-spec> <init-spec>)) ; optional The CLASSVARS and INSTVARS can be just names, in which case those variables will be given the default value of #f, or thye can be specified as (name initial-value) pairs. The specification of INSTVARS can also include forms like so: (name (active init-value get-function set-function)) which indicates that the named variable is an active value. It will have init-value as its initial value. The functions get-function and set-function should be functions of one argument. When the method called GET-name is called, the get-function will be called with the instance variable's current value as argument. When the method called SET-name is called, the set-function will be called with the new value as argument. The (active ...) specifications can be nested arbitrarily deeply, using this form for the init-value. In such a case all the set-functions are called in order, outermost first, when the SET-name method is invoked. All the get-functions are called whenever the GET-name method is invoked, but innermost first. Instance and class variables need not be accessed by SET-name and GET-name methods. They can be treated as lexical variables for the purposes of method definition, so that (say) a variable can just be set by doing a (SET! name ...). An active value is not triggered by such lexical access; only the use of SET-name or GET-name triggers it. The <set-spec> can be settable-variables to cause automatic creation of methods named SET-name for all class and instance variables. It can also be (settable-variables <var1 .. varN>) to cause SET-* methods to be created for only the named variables. The <get-spec> is analogous to <set-spec>, causing creation of GET* methods. The <init-spec> can be inittable-variables so that keywords will be created for all instance variables for use in a call of MAKE-INSTANCE (see below). It can also be (inittable-variables <var1 ... varN>) to make only some be initialisable in this way. Example: (define-class warship (mixins ship military-equipment) (classvars (no-of-warships 0)) (instvars guns shells) (options (settable-variables shells) ; cannot change guns! gettable-variable ; but can ask about anything inittable-variables)) ; and specify when creating. MAKE-INSTANCE (make-instance name '<var1> <val1> ... '<varN> <valN>) returns an instance of class name with those variables bound to those values provided they are declared inittable when the class was defined. Use a variable to bind the instance returned as it does not sideeffect the environment. Example: (define victorious (make-instance warship 'guns 6 ; can init this, but no set-guns method. 'shells 500 ; can init this, & there is a set-shells. 'country "tibet") ; variable presumably inherited from ship? COMPILE-CLASS (compile-class <class>) sets up the environments for classvars and methods. This is done automatically anyway when the first class instance is created, but you may prefer to cause the slight delay to happen at a time of your choosing. The information provided by DESCRIBE-CLASS will be incomplete until the class is `compiled'. Note that the `compilation' of a class does not force the compilation of its mixins, nor is it necessary for the mixins to be compiled before a class (or at all). The compilation merely searches the inheritance graph for the class variables and methods and creates Scheme environments in which these exist together; these environments are used in instance creation, which is why the compilation happens automatically upon creation of the first instance. This `compilation' means that when a message is sent to an instance, the inheritance graph does not have to be re-searched each time. However, if a class has been compiled already and then a method is added to or deleted from the class or any mixin, then there is no need to recompile the class or any other class of which it is a mixin. SCOOPS handles this automatically. CLASS-OF-OBJECT (class-of-object <obj>) simply returns the class-name of the class of an object. NAME->CLASS (name->class '<name>) returns the class named by <name>. METHODS (methods <class>) returns a list of names of methods available to that class and defined within that class. ALL-METHODS (all-methods <class>) returns a list of names of methods available to the class, including inherited methods. CLASSVARS (classvars <class>) returns a list of the names of classvars of the class itself. ALL-CLASSVARS (all-classvars <class>) returns a list of the names of classvars of the class and all those it inherits from. INSTVARS (instvars <class>) returns a list of the names of the instance variables of the class, but not any inherited ones. ALL-INSTVARS (all-instvars <class>) returns a list of the names of instance variables, including inherited ones. MIXINS (mixins <class>) returns names of all of the class's parents. RENAME-CLASS (rename-class (<old> <new>)) redefines <old> as <new>, replacing the internal name flags. GETCV (getcv <class> <class-var>) returns a gettable class-var. SETCV (setcv <class> <class-var> <val>) sets a settable class-var to val. CLASS-COMPILED? (class-compiled? <class>) returns #t if the class has been `compiled' already, either by COMPILE-CLASS or automatically upon instance creation. DESCRIBE (describe <instance-or-class>) prints relevant information about either a class or an instance. If the class has not yet been `compiled' the information will be incomplete. The information will, however, tell you whether the class has been compiled. SEND (send <instance> <message> <optional-arguments>) evaluates <message> with respect to the class and instance and whatever arguments are required. SEND causes an error if the class has no method for the message. You may prefer to use SEND-IF-HANDLES instead. SEND-IF-HANDLES (send-if-handles <instance> <message> <optional-arguments>) Send-if-handles returns #f if the method (message) is inappropiate, otherwise behaves like SEND. DEFINE-METHOD (define-method (<class> <method-name>) <lambda-list> <body>) defines a function that has access to class and instance variables for the class, including inherited ones. All such variables can be regarded as lexical variables in scope for the body of the method; the variables are also accessible by SET-name and GET-name methods if these exist. Any methods accessible to the class can be called as procedures within the body, so there is no need for a pseudovariable called SELF such as is provided by many other objectoriented systems. DELETE-METHOD (delete-method (<class> <method-name>)) destroys the named method of the given class.