Path: hplabsz!hplabs!hpfcso!hpfcbig!tim From: tim@hpfcbig.SDE.HP.COM (Tim Mikkelsen) Newsgroups: comp.lang.lisp.x Subject: Re: intro to XLISP objects Message-ID: <1170005@hpfcbig.SDE.HP.COM> Date: 12 Feb 90 16:23:48 GMT References: <1170004@hpfcbig.SDE.HP.COM> Organization: HP SESD, Fort Collins, CO Lines: 434 XLISP 2.0 OBJECTS PRIMER by Tim I Mikkelsen February 3, 1990 ******************************************************************************** * Copyright (c) 1990 by Tim I. Mikkelsen. * * Permission to use, copy, modify, distribute, and sell this documentation * for any purpose is hereby granted without fee, provided that the above * copyright notice appear in all copies and that both that copyright notice * and this permission notice appear in supporting documentation, and that * the name of Tim Mikkelsen not be used in advertising or publicity * pertaining to distribution of the software without specific, written * prior permission. Tim Mikkelsen makes no representations about the * suitability of this documentation for any purpose. It is provided "as is" * without express or implied warranty. * * TIM MIKKELSEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS DOCUMENTATION, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL TIM MIKKELSEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS DOCUMENTATION AND ACCOMPANYING SOFTWARE. ******************************************************************************** * Document Version: $Header: /users/npm/src/winterp/doc/RCS/XlispOOP.doc,v 2.4 1994/06/06 15:21:17 npm Exp $ ******************************************************************************** ________________________________________________________________ One of the features in the design of XLISP is object-oriented programming. This primer is intended to serve as a very brief introduction to the object facilities of the XLISP 2.0 dialect of LISP. Note that the object features of XLISP are not based on other existing object definitions in other LISP dialects. If you find problems in the primer, I'd appreciate hearing. Tim Mikkelsen 4316 Picadilly Drive Fort Collins, Colorado 80526 PROGRAMMING STYLES ______________________________________________________________________________ There are many programming paradigms (models). Some of the paradigms are procedural, functional, rule-based, declarative and object-oriented. A language can have aspects of one or many of these programming models. Procedure-Oriented The programming paradigm most people are familiar with is the procedural style. The primitives in procedural programming are: subroutines and data structures. Through these primitives, programmers have some limited abilities to share programs and program fragments. C and Pascal are examples of procedural languages. Some procedural languages (such as Modula and ADA) have extensions that provide for better sharing of code. Object-Oriented Programming Object-oriented programming is based on the primitives of objects, classes and messages. Objects are defined in terms of classes. Actions occur by sending a message to an object. An object's definition can be inherited from more general classes. Objective-C and C++ both are object-oriented dialects of the C language. Many dialects of LISP have some object oriented extension (Flavors, Common LOOPS, CLOS and others). There currently is standards work proceeding to add object-oriented programming to Common LISP. Object Oriented Programming So, the object-oriented programming model is based around the concepts of objects, classes and messages. An object is essentially a black box that contains internal state information. You send an object a message which causes the object to perform some operation. Objects are defined and described through classes. One aspect of an object is that you do not have to know what is inside - or how it works - to be able to use it. From a programming point of view, this is very handy. You can develop a series of objects for someone to use. If you need to change what goes on inside, the users of the objects should be unaware. Another aspect of objects is that of inheritance. You can build up new classes from existing classes by inheriting the existing class's functionality and then extending the new definition. For example, you can define a tool class (with various attributes) and then go about creating object instances tool-1, tool-2, and so on. You can also create new sub-classes of the tool class like power-tool. This is also very handy because you don't have to re-implement something if you can build it up from existing code. XLISP OBJECT-ORIENTED PROGRAMMING ______________________________________________________________________________ XLISP OBJECT TERMINOLOGY There are, as previously mentioned, many different languages with object-oriented extensions and facilities. The terminology, operations and styles of these are very different. Some of the main definitions for XLISP's object-oriented extensions are: Object data type The OBJECT DATA TYPE is a built-in data type of XLISP. Members of the object data type are object instances and classes. Object instances An OBJECT INSTANCE is a composite structure that contains internal state information, methods (the code which respond to messages), a pointer to the object instance's defining class and a pointer to the object's super-class. XLISP contains no built-in object instances. Class objects A CLASS OBJECT is, essentially, the template for defining the derived object instances. A class object, although used differently from a simple object instance, is structurally a member of the object data type. It is also contains the linking mechanism that allows you to build class hierarchies (sub-classes and super-classes). XLISP contains two built-in class objects: OBJECT and CLASS. Message selector The MESSAGE SELECTOR is the symbol that is used to select a particular action (Method) from the object. Message The MESSAGE is the combination of the message selector and the data (if any) to be sent to the object. Method The METHOD is the actual code that gets executed when the object receives the Message. SENDING MESSAGES The mechanism for sending messages to XLISP objects is via the SEND function. It takes an object, a message selector and various optional arguments (depending on the message selector). The way that a user creates a new object is to send a :NEW message to a previously defined class. The result of this SEND will return an object, so this is normally preceded by a SETQ. The values shown in the examples that follow may not match what you see if you try this on your version of XLISP - this is not an error. The screens that are used in the various examples are similar to what you should see on your computer screen. The ">" is the normal XLISP prompt (the characters that follow the prompt is what you should type in to try these examples). ________________________________________________________________ | | > (setq my-object (send object :new)) | # |________________________________________________________________ The object created here is of limited value. Most often, you create a class object and then you create instances of that class. So in the following example, a class called MY-CLASS is created that inherits its definition from the a built-in CLASS definition. Then two instances are created of the new class. ________________________________________________________________ | | > (setq my-class (send class :new '())) | # | | > (setq my-instance (send my-class :new)) | # | | > (setq another-instance (send my-class :new)) |# |________________________________________________________________ CLASSES Previously, a :NEW message was used to create an object. The message used to see what is in an object is the :SHOW message. ________________________________________________________________ | | > (send my-class :show) | Object is #, Class is # | MESSAGES = NIL | IVARS = NIL | CVARS = NIL | CVALS = NIL | SUPERCLASS = # | IVARCNT = 0 | IVARTOTAL = 0 | # |________________________________________________________________ From the display of the MY-CLASS object you can see there are a variety of components. The components of a class are: Class Pointer This pointer shows to what class the object (instance or class) belongs. For a class, this always points to the built-in object CLASS. This is also true of the CLASS object, its class pointer points to itself. Superclass Pointer This pointer shows what the next class up the class hierarchy is. If the user does not specify what class is the superclass, it will point to the built-in class OBJECT. Messages This component shows what messages are allowed for the class, and the description of the method that will be used. If the method is system-defined, it will show up in the form of '#'. Remember that the class hierarchy (through the Superclass Pointer) is searched if the requested message is not found in the class. Instance Variables This component lists what instance variables will be created when an object instance is created. If no instances of the class exist, there are no Instance Variables. If there are 5 instances of a class, there are 5 complete and different groups of the Instance Variables. Class Variables The CLASS VARIABLES (CVAR) component and Values lists what class variables exist within the class. The Class Values (CVAL) component shows what the current values of the variables are. Class Variables are used to hold state information about a class. There will be |Bone of each|A of the Class Variables, independent of the number of instances of the class created. A BETTER EXAMPLE The example previously shown does work, but the class and instances created don't really do anything of interest. The following example sets up a tool class and creates some tool instances. ________________________________________________________________ | | > (setq my-tools (send class :new '(power moveable operation))) | # | | > (send my-tools :answer :isnew '(pow mov op) | '((setq power pow) | (setq moveable mov) | (setq operation op))) | # | | > (setq drill (send my-tools :new 'AC t 'holes)) | # | | > (setq hand-saw (send my-tools :new 'none t 'cuts)) | # | | > (setq table-saw (send my-tools :new 'AC nil 'cuts)) | # |________________________________________________________________ So, a class of objects called MY-TOOLS was created. Note that the class object MY-TOOLS was created by sending the :NEW message to the built-in CLASS object. Within the MY-TOOL class, there are three instances called DRILL, HAND-SAW and TABLE-SAW. These were created by sending the :NEW message to the MY-TOOLS class object. Notice that the parameters followed the message selector. INSTANCES The following is a display of the contents of some of the previously created instances: ________________________________________________________________ | | > (send drill :show) | Object is #, Class is # | POWER = AC | MOVEABLE = T | OPERATION = HOLES | # | | > (send hand-saw :show) | Object is #, Class is # | POWER = NONE | MOVEABLE = T | OPERATION = CUTS | # |________________________________________________________________ From the display of these instances you can see there are some components and values. The components of an instance are: Class Pointer This pointer shows to which class the current object instance belongs. It is through this link that the system finds the methods to execute for the received messages. Instance Variables The Instance Variables (IVAR) component and Values lists what variables exist within the instance. The Instance Values component holds what the current values of the variables are. Instance Variables are used to hold state information for each instance. There will be a group of Instance Variables for each instance. METHODS There have been a few of the messages and methods in XLISP shown to this point (:NEW and :SHOW). The following are the methods built into XLISP: :ANSWER The :ANSWER method allows you to define or change methods within a class. :CLASS The :CLASS method returns the class of an object. :ISNEW The :ISNEW method causes an instance to run its initialization code. When the :ISNEW method is run on a class, it resets the class state. This allows you to re-define instance variables, class variables, etc. :NEW The :NEW method allows you to create an instance when the :NEW message is sent to a user-defined class. The :NEW method allows you to create a new class (when the :NEW message is sent to the built-in CLASS). :SHOW The :SHOW method displays the instance or class. SENDING MESSAGES TO A SUPERCLASS In addition to the SEND function, there is another function called SEND-SUPER. The SEND-SUPER function causes the specified message to be performed by the superclass method. This is a mechanism to allow chaining of methods in a class hierarchy. This chaining behavior can be achieved by creating a method for a class with the :ANSWER message. Within the body of the method, you include a SEND-SUPER form. This function is allowed only inside the execution of a method of an object. OBJECT AND CLASS The definition of the built-in class OBJECT is: ________________________________________________________________ | | > (send object :show) | Object is #, Class is # | MESSAGES = ((:SHOW . #) | (:CLASS . #) | (:ISNEW . #)) | IVARS = NIL | CVARS = NIL | CVALS = NIL | SUPERCLASS = NIL | IVARCNT = 0 | IVARTOTAL = 0 | # |________________________________________________________________ Note that OBJECT is a class - as opposed to an "instance-style" object. OBJECT has no superclass, it is the top or root of the class hierarchy. OBJECT's class is CLASS. ________________________________________________________________ | | > (send class :show) | Object is #, Class is # | MESSAGES = ((:ANSWER . #) | (:ISNEW . #) | (:NEW . #)) | IVARS = (MESSAGES IVARS CVARS CVALS SUPERCLASS | IVARCNT IVARTOTAL) | CVARS = NIL | CVALS = NIL | SUPERCLASS = # | IVARCNT = 7 | IVARTOTAL = 7 | # |________________________________________________________________ CLASS has a superclass of OBJECT. It's class is itself - CLASS. Path: hplabsz!hplabs!hpfcso!hpfcbig!tim From: tim@hpfcbig.SDE.HP.COM (Tim Mikkelsen) Newsgroups: comp.lang.lisp.x Subject: Re: intro to XLISP objects Message-ID: <1170006@hpfcbig.SDE.HP.COM> Date: 12 Feb 90 16:24:20 GMT References: <1170004@hpfcbig.SDE.HP.COM> Organization: HP SESD, Fort Collins, CO Lines: 228 A MORE REALISTIC EXAMPLE ______________________________________________________________________________ The following is an example, using the idea of tools again. It contains a hierarchy of tool classes. The top of the class hierarchy is TOOLS. HAND-TOOLS and SHOP-TOOLS are sub-classes of TOOLS. The example creates instances of these sub-classes. It is possible to extend this example in various ways. One obvious extension would be to create a third tier of classes under HAND-TOOLS that could contain classes like drills, screwdrivers, pliers and so on. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; File name: tools.lsp ; Author: Tim Mikkelsen ; Description: Object-oriented example program ; Language: XLISP 2.0 ; ; Date Created: 10-Jan-1988 ; Date Updated: 2-Apr-1989 ; ; (c) Copyright 1988, by Tim Mikkelsen, all rights reserved. ; Permission is granted for unrestricted non-commercial use. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Define the superclasses and classes ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; make TOOLS superclass ; with a different :ISNEW method ; added methods are :BORROW and :RETURN ; class variables are NUMBER contains # of tool instances ; ACTIVE-LIST contains list of current objects ; instance variables are POWER list - (AC BATTERY HAND) ; MOVEABLE CAN-CARRY or CAN-ROLL or FIXED ; OPERATIONS list ; MATERIAL list - (WOOD METAL PLASTIC ...) ; PIECES list ; LOCATION HOME or person's name ; (setq tools (send class :new '(power moveable operations material pieces location) '(number active-list))) (send tools :answer :isnew '() '((if (null number) (setq number 1) (setq number (1+ number))) (setq active-list (cons self active-list)) (setq location 'home))) (send tools :answer :borrow '(by-who) '((if (eq location 'home) (setq location by-who) (print "you can't")))) (send tools :answer :return '() '((if (eq location 'home) (print "got it already") (setq location 'home)))) ; ; make HAND-TOOLS class ; with a different :ISNEW method ; new instance variable WEIGHT of pounds ; the rest is inherited from TOOLS ; (setq hand-tools (send class :new '(weight) '() tools)) (send hand-tools :answer :isnew '(pow op mat parts w-in) '((setq power pow) (setq moveable 'can-carry) (setq operations op) (setq material mat) (setq pieces parts) (setq weight w-in) (send-super :isnew))) ; ; make SHOP-TOOLS class ; with a different :ISNEW method ; no new instance variables ; the rest is inherited from TOOLS ; (setq shop-tools (send class :new '() '() tools)) (send shop-tools :answer :isnew '(pow mov op mat parts) '((setq power pow) (setq moveable mov) (setq operations op) (setq material mat) (setq pieces parts) (send-super :isnew))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Create instances of various tool classes ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setq hand-drill (send hand-tools :new ; make an instance - HAND-DRILL '(ac) '(drill polish grind screw) '(wood metal plastic) '(drill drill-bits screw-bits buffer) '2.5)) (setq table-saw (send shop-tools :new ; make an instance - TABLE-SAW '(ac) 'fixed '(rip cross-cut) '(wood plastic) '(saw blades fence))) (setq radial-arm (send shop-tools :new ; make an instance = RADIAL-ARM '(ac) 'can-roll '(rip cross-cut) '(wood plastic) '(saw blades dust-bag))) The following session shows how to use the tool definitions from this better example. The example starts at the OS shell and brings up xlisp running the file 'tools.lsp'. ________________________________________________________________ | | cmd? xlisp tools | ; loading "init.lsp" | ; loading "tools.lsp" | > (send hand-drill :borrow 'fred) | FRED | | > (send table-saw :return) | "got it already" | "got it already" | | > (send hand-drill :borrow 'joe) | "you can't" | "you can't" | | > (send hand-drill :return) | HOME |________________________________________________________________ So, Fred was able to borrow the HAND-DRILL. When an attempt was made to return the TABLE-SAW, it was already at home. A second attempt to borrow the HAND-DRILL indicated that "you can't" because it was already lent out. Lastly, the HAND-DRILL was returned successfully. (Note that the "got it already" and "you can't" strings show up twice in the display because the methods both print and return the string.) The following session shows the structure of the TOOLS object: ________________________________________________________________ | | > (send tools :show) | Object is #, Class is # | MESSAGES = ((:RETURN . #) | (:BORROW . #) | (:ISNEW . #)) | IVARS = (POWER MOVEABLE OPERATIONS MATERIAL PIECES LOCATION) | CVARS = (NUMBER ACTIVE-LIST) | CVALS = #(3 (# | # | #)) | SUPERCLASS = # | IVARCNT = 6 | IVARTOTAL = 6 | # |________________________________________________________________ The two TOOLS sub-classes HAND-TOOLS and SHOP-TOOLS structure looks like: ________________________________________________________________ | | > (send hand-tools :show) | Object is #, Class is # | MESSAGES = ((:ISNEW . #)) | IVARS = (WEIGHT) | CVARS = NIL | CVALS = NIL | SUPERCLASS = # | IVARCNT = 1 | IVARTOTAL = 7 | # | | > (send shop-tools :show) | Object is #, Class is # | MESSAGES = ((:ISNEW . #)) | IVARS = NIL | CVARS = NIL | CVALS = NIL | SUPERCLASS = # | IVARCNT = 0 | IVARTOTAL = 6 | # |________________________________________________________________ The class HAND-TOOLS has an instance HAND-DRILL which looks like: ________________________________________________________________ | | > (send hand-drill :show) | Object is #, Class is # | WEIGHT = 2.5 | POWER = (AC) | MOVEABLE = CAN-CARRY | OPERATIONS = (DRILL POLISH GRIND SCREW) | MATERIAL = (WOOD METAL PLASTIC) | PIECES = (DRILL DRILL-BITS SCREW-BITS BUFFER) | LOCATION = HOME | # |________________________________________________________________