\input imbasic.tex
\def\chapnum{0}
\setcount0 0
\def\draftflg{F}

\rm{}



\vfill\eject
\setcount0 0
\def\chapnum{0}
\def\chapname{THE LOOPS MANUAL}
\def\noheaderonce{T}


\bf{}\ctrline{THE LOOPS MANUAL}
\vskip 30pt

\rm{}by Daniel G. Bobrow (Xerox PARC) & Mark Stefik (Xerox PARC)





\sl{}Abstract:\rm{}  LOOPS adds data, object, and rule oriented programming to the procedure oriented programing of Interlisp.  In object oriented programming, behavior is determined by responses of instances of classes to messages sent between these objects, with no direct access to the internal structure of an object.  This approach makes it convenient to define program interfaces in terms of message protocols.  Data oriented programming is a dual of object oriented programming, where behavior can occur as a side effect of direct access to (permanent) object state.  This makes it easy to write programs which monitor the behavior of other programs.  Rule oriented programming is an alternative to programming in LISP.  Programs in this paradigm are organized around recursively composable sets of pattern-action rules for use in expert system design.  Rules make it convenient for describing flexible responses to a wide range of events.  LOOPS is integrated into Interlisp, and thus provides access to the standard procedure oriented programming of Lisp, and use of the extensive environmental support of the Interlisp-D system  

Our experience suggests that programs are easier to build in a language when there is an available paradigm that matches the structure of the problem.  The paradigms described here offer distinct ways of partitioning the organization of a program, as well as distinct ways of viewing the significance of side effects.  LOOPS provides all these paradigms within a single environment.  This manual is intended as the primary documentation for users of LOOPS.  It describes the concepts and the programming facilities, and gives examples and scenarios for using LOOPS.








\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}INTRODUCTION

\rm{}\penalty 2000
{\open 1=ChapLoops.IMPAGE  }{\send1{(INTRODUCTION.IM;3 56 \count0)}}\penalty 2000
\mark{INTRODUCTION}
\penalty 2000
\vskip10pt
\penalty 2000
Four distinct paradigms of programming available in the computer science community today are oriented around procedures, objects, data access and rules.  Usually these paradigms are embedded in different languages.  LOOPS is designed to incorporate all of them within the Interlisp programming environment, to allow users to choose the style of programming which best suits their application.

\sl{}Procedure Oriented Programming:\rm{}  Lisp is a procedure oriented language; the procedure oriented paradigm is the dominant one provided in most programming languages today.  Two separate kinds of entities are distinguished: procedures and data.  Procedures are active and data are passive.  The ability to compose procedures out of instructions and to invoke them is central to organizing programs using these languages.  This is a major source of leverage in synthesizing programs.  Side effects happen when separate procedures share a data structure and change parts of it independently.	  

\sl{}Object Oriented Programming:\rm{}  This paradigm was pioneered by Smalltalk, and has its roots in SIMULA and in the concept of data abstraction.  In contrast with the procedure-oriented paradigm, programs are not primarily partitioned into procedures and separate data.  Rather, a program is organized around entities called objects that have aspects of both procedures and data.  Objects have local procedures (methods) and local data (variables).  All of the action in these languages comes from sending messages between objects.  Objects provide local interpretation of the message form. 

The object-oriented paradigm is well suited to applications where the description of entities is simplified by the use of uniform protocols.  For example in a graphics application, windows, lines and composite structures could be represented as objects that respond to a uniform set of messages (i.e., \lisp{}Display\rm{}, \lisp{}Move\rm{}, and \lisp{}Erase\rm{}).  An important feature of these languages is an inheritance network, which makes it convenient to define objects which are \sl{}almost like\rm{} other objects.  This works together with the use of uniform protocols because specialized objects usually share the protocols of their super classes.	  

\sl{}Data Oriented Programming:\rm{}  In both of the previous paradigms, the invocation of procedures (either by direct procedure call or by message sending) is convenient for creating a description of a single process.  In the data-oriented programming, action is potentially triggered when data are accessed.  Data oriented programming makes use of long term storage of objects with implicit links from structures to actions.

Data oriented programming is appropriate for interfacing between nearly independent processes.  A good example of this is the construction of a viewer for an independent traffic simulation process.  The viewer provides a visual display of the changing traffic simulation process without affecting the code for the simulation.  This independence means that the two processes can be written and understood separately.  It means that the interactions between them can often be controlled without changing them.

\sl{}Rule Oriented Programming:\rm{}  In rule oriented programming, the behavior of the system is determined by sets of condition-action pairs.  These \sl{}RuleSets\rm{} play the same role as subroutines in the procedure oriented metaphor.  Within a RuleSet, invocation of rules is guided largely by patterns in the data.  In the typical case, rules correspond to nearly-independent patterns in the data.  The rule-oriented approach is convenient for describing flexible responses to a wide range of events characterized by the structure of the data.

Our experience suggests that programs are easier to build in a language when there is an available paradigm that matches the structure of the problem.  A variety of programming paradigms gives breadth to a programming language.  The paradigms described here offer distinct ways of partitioning the organization of a program, as well as distinct ways of viewing the significance of side effects.  LOOPS provides all these paradigms within the Interlisp environment [Xerox83].  In principle, the data-oriented programming can be used with either the object-oriented or the procedure-oriented paradigms.  In LOOPS, we have combined it only with variables in the object-oriented metaphor.  

\sl{}Summary:\rm{}  LOOPS adds data, object, and rule oriented programming to Interlisp.  In object oriented programming, behavior is determined by responses of instances of classes to messages sent between these objects, with no direct access to the internal structure of an object.  This approach makes it convenient to define program interfaces in terms of message protocols.  LOOPS provides:



\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}inheritance of instance behavior and structure from multiple super classes

\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}user extendible property list descriptions of classes, their variables, and their methods

\parshape 1    0
pt  462pt {}

\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}composite objects - templates for related objects that are instantiated as a group.

\parshape 1    0pt  462pt {}


Data oriented programming is a dual of object oriented programming, where behavior can occur as a side effect of direct access to (permanent) object state.  This makes it easy to write programs which monitor the behavior of other programs.  LOOPS provides:



\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}active values for object variables which can cause a procedure invocation on setting or fetching


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}integration with facilities for long term storage of objects in shared knowledge bases

\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   23
pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}support for incremental updates (layers), and the representation of multiple alternatives.

\parshape 1    0pt  462pt {}

Rule oriented programming is an alternative to programming in LISP.  Programs in this paradigm are organized around recursively composable sets of pattern-action rules for use in expert system design.  Rules make it convenient for describing flexible responses to a wide range of events.  LOOPS provides:



\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}a concise syntax for pattern matching and rule set construction

\parshape 1    0pt  462pt {}

\vskip 10pt

\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}use of objects as working memory for rule sets

\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}primitives for executing, stepping and suspending tasks based on ruleSets

\parshape 1    0
pt  462pt {}

\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}compilation of ruleSets into Lisp code for efficient execution

\parshape 1    0pt  462pt {}

LOOPS is integrated into Interlisp.  LOOPS provides:



\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}classes and instances as Interlisp file objects


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   23pt  439pt {}\noindent\hbox to 0pt{\hskip-23pt{$\bullet$}\hskip0pt plus 1000pt minus 1000pt}pseudoClasses to field messages to standard Interlisp datatypes

\parshape 1    0pt  462pt {}

This manual is intended as the primary documentation for users of LOOPS.  It describes the concepts and the programming facilities, and gives examples and scenarios for using LOOPS.




\vskip10pt

\bf{}\noindent\save0\hbox{1.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Intellectual Precursors

\rm{}\penalty 2000
{\send1{(INTRODUCTION.IM;3 6867 \count0)}}\penalty 2000
\mark{Intellectual Precursors}
\penalty 2000
\vskip10pt
\penalty 2000
LOOPS grew out of our research in a knowledge representation language (called Lore) for use in a project to create an \sl{}expert assistant\rm{} for designers of integrated digital systems.  Along the way, we discovered that we needed to experiment with alternative versions of the representation language.  A core of features was identified that we wanted to keep constant in our experiments.  This core became a data and object-oriented programming system with many features not found in other available systems.  Many of the features (e.g., active values, data bases, and composite objects) were motivated by the needs of our project, but we they would be useful for many other applications.  LOOPS has been sufficiently useful and general that we decided to make it available outside of our group.	

The design of LOOPS owes an intellectual debt to a number of other systems, including: 

(1) Smalltalk ([Goldberg82], [Goldberg81], [Ingalls78]), which has pioneered many of the concepts of object-oriented programming.

(2) Flavors [Cannon82], which supports this style of programming in the MIT Lisp Machine environment and which confronted non-hierarchical inheritance.

(3) PIE [Goldstein80], which provided facilities for incremental, sharable data bases.

(4) KRL [Bobrow77], which explored many issues in the design of frame-based knowledge representation languages and which provoked much additional work in this area.

(5) UNITS [Stefik79], which provided a substantial testbed for experiments in problem solving that have guided our decisions about the importance of several language features.

(6) EMYCIN [VanMelle80] which showed the power of rule oriented programming for building expert systems.

While all of these languages provided ideas, none of them was quite right for our current needs.  For example, Smalltalk supports only hierarchical inheritance and does not have a layered data base, active values, or property lists on variables.  PIE  and KRL are not easily supportable or extendable.  Flavors does not run on the machines available to us.  UNITS was the closest existing language to our needs, but we wanted to change many of its features.  Since we have compared these languages and traced the intellectual history elsewhere [Bobrow82], we will not pursue that further in this document.  

In designing LOOPS, we wanted a general inheritance mechanism, a way of attaching access-triggered procedures to variables, a way of instantiating composite objects recursively, and a way of creating permanent databases of objects that can be shared and updated incrementally.  		

In tension with the desire for extensive language features was a desire to keep LOOPS small so that it would be easy to understand and to implement.  To this end we have tried to create a small repertoire of powerful features that work well together.









\vskip10pt

\bf{}\noindent\save0\hbox{1.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Acknowledgments

\rm{}\penalty 2000
{\send1{(INTRODUCTION.IM;3 9895 \count0)}}\penalty 2000
\mark{Acknowledgments}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}from the LOOPS Manual:\rm{}

Thanks to Alan Bell, Harry Barrow, Harold Brown, Gordon Foyster, Phil Gerring and Gordon Novak, Chris Tong, Schlomo Weiss, Terry Winograd and the other members of the KBVLSI project (past and present) for bug reports and suggestions, and for enduring the wait for it to mature into existence while so many things have been pressing.  Special thanks to Johan de Kleer for extensive discussions of design issues, and to Richard Fikes, Adele Goldberg, Danny Hillis, Dan Ingalls, and Gordon Novak for comments on earlier drafts of this manuscript.  We are grateful to Larry Masinter and Bill Van Melle for help on the integration of LOOPS with Lisp, and to the Interlisp-D group for unfailing support and encouragement.  Thanks also to Lynn Conway for encouraging this work and to the Xerox Corporation for providing the intellectual and computing environments in which it could be done.

\sl{}from the Rules Manual:\rm{}

Special thanks to Danny Berlin and Lynn Conway for many suggestions and for the patience it takes to be the first real users of something new.  Sanjay Mittal and Terry Winograd offered helpful criticisms and advice on the documentation and concepts of the rule language.  Larry Masinter and Bill van Melle have provided substantial support in the entire Loops enterprise with Interlisp-D.  Thanks to the Xerox Corporation and George Pake of Xerox PARC for providing the stimulating environment and computational facilities that made this work possible.










\vskip10pt

\bf{}\noindent\save0\hbox{1.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}References

\rm{}\penalty 2000
{\send1{(INTRODUCTION.IM;3 11478 \count0)}}\penalty 2000
\mark{References}
\penalty 2000
\vskip10pt
\penalty 2000
[Aiello81]  Aiello, N., Bock, C., Nii, H. P., White, W. C., \sl{}AGE Reference Manual\rm{}.  Technical Report, Heuristic Programming Project, Computer Science Department, Stanford University, October 1981.

[Bobrow82]  Bobrow, D. G., & Stefik, M. J. Introducing new programming metaphors to LISP.  (submitted to \sl{}Communications of the Association for Computing Machinery\rm{}).

[Bobrow80]  Bobrow, D. G., & Goldstein, I. P. Representing design alternatives. \sl{}Proceedings of the AISB Conference\rm{}, Amsterdam, 1980.

[Bobrow77a]  Bobrow, D. G., & Winograd, T. An overview of KRL, a knowledge representation language, \sl{}Cognitive Science\rm{} 1:1, 1977, pp 3-46.

[Bobrow77b]  Bobrow, D. G., & Winograd, T.  Experience with KRL-0, one cycle of a knowledge representation language, \sl{}Proceedings of the Fifth International Joint Conference on Artificial Intelligence\rm{}, Cambridge, Mass. August, 1977, pp 213-222.

[Cannon82]  Cannon, H. I.  Flavors: a non-hierarchical approach to object-oriented programming, \sl{}personal communication\rm{}, 1982.

[Consumers80]  Anon, Washing Machines.  \sl{}Consumer Reports\rm{}, November 1980, pp. 679-684.

[Erman81]  Erman, L. D., London, P. E., Fickas, S. F.  The design and an example use of Hearsay-III. \sl{}Proceedings of the Seventh International Joint Conference on Artificial Intelligence\rm{}, August 1981, pp. 409-415.

[Fain81]  Fain, J., Gorlin, D., Hayes-Roth, F., Rosenschein, S., Sowizral, H., Waterman, D.  \sl{}The ROSIE Reference Manual\rm{}, Rand Note N-1647-ARPA, Rand Corporation, December 1981.

[Feigenbaum78]  Feigenbaum, E. A., The art of artificial intelligence: themes and case studies of knowledge engineering, \sl{}AFIPS Conference Proceedings\rm{} 47 National Computer Conference, 1978, pp. 227--240.

[Forgy81]  Forgy, C. L.  \sl{}OPS5 User's Manual\rm{}.  Technical Report CMU-CS-81-135.  Department of Computer Science, Carnegie-Mellon University, Pittsburgh, Pennsylvania, July 1981.

[Goldberg82]  Goldberg, A., Robson, D., Ingalls, D.  \sl{}Smalltalk-80: The language and its implementation\rm{}. Reading, Massachusetts: Addison-Wesley (in press).

[Goldberg81]  Goldberg, A. Introducing the Smalltalk-80 System, \sl{}Byte\rm{} 6:8, August 1981.

[Goldstein80]  Goldstein, I. P., & Bobrow, D. G.  Extending object oriented programming in Smalltalk. \sl{}Proceedings of the Lisp Conference\rm{}, Stanford University, 1980.

[Ingalls78]  Ingalls, D. H. The Smalltalk-76 programming system: design and implementation. \sl{}Conference Record of the Fifth Annual ACM Symposium on Principles of Programming Languages\rm{}, Tucson, Arizona, January 1978, pp 9-16. 

[Maytag]  Anon.  \sl{}Operating Instructions for Model A510\rm{}.  Printed by the Maytag Company, Newton Iowa 50208.

[Stefik82]  Stefik, M., Aikins,5 J., Balzer, R., Benoit, J., Birnbaum, L., Hayes-Roth, F., Sacerdoti, E.  The organization of expert systems: a tutorial.  \sl{}Artificial Intelligence\rm{}, 18:2, March 1982, pp. 135-173.

[Stefik79]  Stefik, M. An examination of a frame-structured representation system. \sl{}Proceedings of the Sixth International Joint Conference on Artificial Intelligence\rm{}, Tokyo, Japan, August 1979, pp. 845-852.

[VanMelle80] Emycin ... To be filled in

[Weinreb81]  Weinreb, D., & Moon, D. \sl{}Lisp Machine Manual\rm{}, Massachusetts Institute of Technology, 1981

[Xerox83]  \sl{}Interlisp Reference Manual\rm{}, Xerox Palo Alto Research Center, October, 1983.


















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}OVERVIEW

\rm{}\penalty 2000
{\send1{(OVERVIEW.IM;4 48 \count0)}}\penalty 2000
\mark{OVERVIEW}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip10pt

\bf{}\noindent\save0\hbox{2.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Structure of Classes and Instances

\rm{}\penalty 2000
{\send1{(OVERVIEW.IM;4 149 \count0)}}\penalty 2000
\mark{Structure of Classes and Instances}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}Classes:\rm{}{\send1{(OVERVIEW.IM;4 179 \count0)}}  A class is a description of one or more similar objects.  An \sl{}instance\rm{} is an object described by a particular class.  Every object within LOOPS is an instance of exactly one class.  Classes themselves are instances of a class, usually the one called \lisp{}Class\rm{}.  Classes whose instances are classes are called \sl{}metaclasses\rm{}.

\sl{}Variables:\rm{}{\send1{(OVERVIEW.IM;4 548 \count0)}}  LOOPS supports two kinds of variables - class variables and instance variables.  Class variables are used to contain information shared by all instances of the class.  A class variable is typically used for information about a class taken as a whole.  Instance variables contain the information specific to an instance.  Both kinds of variables have names, values, and other properties.  A class describes the structure of its instances by specifying the names and default values of instance variables.  For example, the class \lisp{}Point\rm{} might specify two instance variables, \lisp{}x\rm{} and \lisp{}y\rm{} with default values of \lisp{}0\rm{}, and a class variable, \lisp{}lastSelectedPoint\rm{}, used by methods associated with all instances of class \lisp{}Point\rm{}.  LOOPS also allows {\lquotes}variable length{\rquotes} classes, which have some instance variables that are referenced by numerical index.

\sl{}Methods:\rm{}{\send1{(OVERVIEW.IM;4 1450 \count0)}}  A class specifies the behavior of its instances in terms of their response to \sl{}messages\rm{}.  The class associates \sl{}selectors\rm{}{\send1{(OVERVIEW.IM;4 1598 \count0)}} (LISP atoms) with \sl{}methods\rm{}, the Interlisp functions that respond to the messages.  All instances of a class use the same selectors and methods.  Any difference in response by two instances of the same class is determined by a difference in the values of their instance variables.  For example, \lisp{}PrintOn\rm{} is used as a selector for the message which knows how to print out a representation of an object on a file.

\sl{}Properties:\rm{}{\send1{(OVERVIEW.IM;4 2055 \count0)}}  LOOPS provides user-extendible property lists for classes, their variables, and their methods.  Property lists provide places for storing documentation and additional kinds of information.  A property list on a variable is used to store additional information about both the variable and its value.  For example, in a knowledge engineering application, a property list for an instance variable could be used to store such information as \sl{}support\rm{} (i.e., reasons for believing a value), \sl{}certainty factors\rm{} (i.e., numeric assessments of degree of belief), \sl{}constraints\rm{} on values, \sl{}dependencies\rm{} (i.e., relationships to other variables), and \sl{}histories\rm{} (i.e., previous values).

\sl{}Metaclasses:\rm{}{\send1{(OVERVIEW.IM;4 2787 \count0)}}  Classes themselves are instances of some class.  When we want to distinguish classes whose instances are classes, we call them metaclasses, after the Smalltalk usage.  When a class is sent a message, its metaclass determines the response.  For example, instances of a class are created by sending the class the message \lisp{}New\rm{}.  For most classes, this method is provided by the standard metaclass for classes: \lisp{}Class\rm{}.  The user can create other metaclasses to perform specialized initialization.  The metaclass for \lisp{}Class\rm{} itself (called \lisp{}MetaClass\rm{}) contains the \lisp{}New\rm{} method for making classes.  Another useful metaclass provided in the system is \lisp{}AbstractClass\rm{}.  It is used for classes that are placeholders in the inheritance network that it would not make sense to instantiate.  Its response to a \lisp{}New\rm{} message is to cause an error.




\vskip 10pt
{\send1{(OVERVIEW.IM;4 3703 \count0)}}\parshape 1   46
pt  416pt {}

\lisp{}{\nofill{}[DEFCLASS AreaBudget
   (MetaClass Class    EditedBy (* dgb "15-Feb-82 14:32 ") 
                  doc
(* * This is a sample class chosen to illustrate the syntax
 of classes in LOOPS.  Commentary on the class is inserted
 in a standard property in the class.  -- e.g. Budgets are ...))
   (Supers OwnedObject Budget)
   (ClassVariables (maxBase 25000))
   (InstanceVariables
      (owner {\char'43}{\char'44}VLSI doc (* organizational area that owns budget) )
      (base 1000 doc (* The initial amount of money))
      (overhead 2.25 doc (* Multiplied by base to get total.))
      (employees NIL doc (* list of employees in this area))
      (manager NIL doc (* manager of this area))
      (total {\char'43}(SHARED getTotal UpdateNotAllowed) 
         doc (* value of total is computed using active value.))
   (Methods
      (Report AreaBudget.Report doc (* Prints out a budget report))
      (StoreBase AreaBudget.StoreBase
         doc (* store base value checking maxBase))]\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 1.   Example of a class definition in LOOPS.  The class, called \lisp{}AreaBudget\rm{}, inherits variables and methods from both of its super classes (\lisp{}OwnedObject\rm{} and \lisp{}Budget\rm{}).  The form of the definition here does not show inherited information, only the changes and additions.  In this example the new class variable \lisp{}maxBase\rm{} is introduced, and six instance variables (\lisp{}owner\rm{}, \lisp{}base\rm{}, \lisp{}overhead\rm{}, \lisp{}employees\rm{}, \lisp{}manager\rm{}, and \lisp{}total\rm{}) are defined.  The \lisp{}Methods\rm{} declaration names the Interlisp functions that implement the methods.  For example, \lisp{}AreaBudget.Report\rm{} is the name of a function that implements the \lisp{}Report\rm{} method for instances of \lisp{}AreaBudget\rm{}.


\parshape 1    0pt  462pt {}









\vskip10pt

\bf{}\noindent\save0\hbox{2.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Inheriting Variables and Methods

\rm{}\penalty 2000
{\send1{(OVERVIEW.IM;4 5571 \count0)}}\penalty 2000
\mark{Inheriting Variables and Methods}
\penalty 2000
\vskip10pt
\penalty 2000
Inheritance is an important tool for organizing information in objects.  It enables the easy creation of objects that are {\lquotes}almost like{\rquotes} other objects with a few incremental changes.  Inheritance avoids the user have to specify redundant information and simplifies updating, since information that is common need be changed in only one place.

LOOPS objects exist in an \sl{}inheritance network\rm{}{\send1{(OVERVIEW.IM;4 5994 \count0)}} of classes.  An object inherits its instance variable description and message responses.  All descriptions in a class are inherited by a subclass unless overridden in the subclass.  For methods and class variables, this is implemented by a runtime search for the information, looking first in the class, and then at the super classes specified by its \sl{}supers list\rm{}.{\send1{(OVERVIEW.IM;4 6382 \count0)}}  For instance variables, no search is made at run time;  default values are cached in the class, and are updated if any super is changed, thus maintaining the same semantics as the search.  Each class can specify inheritance of structure and behavior from any number of super classes in its supers list.	

\sl{}Hierarchy:\rm{}  In the simplest case, each class specifies only one super class.  If the class \lisp{}A\rm{} has the supers list \lisp{}(B)\rm{}, a one element list containing \lisp{}B\rm{}, then all of the instance variables specified local to \lisp{}A\rm{} are added to those specified for \lisp{}B\rm{}, recursively.  That is, \lisp{}A\rm{} gets all those instance variables described in \lisp{}B\rm{} and all of \lisp{}B\rm{}'s supers.  In this case one obtains strict inheritance hierarchy as in Smalltalk. 

Any conflict of variable names is resolved by using the description closer to \lisp{}A\rm{} in traversing up the hierarchy to its root at the class \lisp{}Object\rm{}.  Method lookup uses the same conflict resolution.  The method to respond to a message is obtained by first searching in \lisp{}B\rm{}, and then searching recursively in \lisp{}B\rm{}'s supers list.  An example of this is given in figure X.X.




\vskip 10pt
{\send1{(OVERVIEW.IM;4 7605 \count0)}}
\parshape 1   46pt  416pt {}

\stretchyspaceskip{}\ragged 9999{}

\parshape 0 {}

\vskip 10pt
\hbox{\vbox{

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 92pt{Class}\cr\noalign{\hskip15pt}
\hbox par 92pt{Super}\cr\noalign{\hskip15pt}
\hbox par 92pt{InstanceVariables}\cr\noalign{\hskip15pt}
\hbox par 92pt{Methods}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 92pt{\lisp{}Object\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}NIL\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{none}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(s4 M6)\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 92pt{\lisp{}C\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}Object\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(w 7)\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(s2 M4) (s3 M5)\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 92pt{\lisp{}B\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}C\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(y 4) (z 3)\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(s1 M2) (s2 M3)\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 92pt{\lisp{}A\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}B\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(x 1) (y 0)\rm{}}\cr\noalign{\hskip15pt}
\hbox par 92pt{\lisp{}(s1 M1)\rm{}}\cr\noalign{\hskip15pt}
}}}}

\ragged 0{}\normalspaceskip{}

\parshape 1   46pt  416pt {}


\parshape 1    0pt  462pt {}\parshape 1   46
pt  416pt {}Figure 2.   In the definitions given in the above chart, an instance of \lisp{}A\rm{} would be given four instance variables, \lisp{}w\rm{}, \lisp{}y\rm{}, \lisp{}z\rm{}, and \lisp{}x\rm{} in that order.  The default value for \lisp{}y\rm{} would be \lisp{}0\rm{}, which overrides the default value of \lisp{}y\rm{} inherited from \lisp{}B\rm{}.  The instance would also respond to the four messages with selector \lisp{}s1\rm{}, \lisp{}s2\rm{}, \lisp{}s3\rm{}, and \lisp{}s4\rm{}.  The method used for responding to \lisp{}s1\rm{} is \lisp{}M1\rm{}, which is said to override \lisp{}M2\rm{} as the implementation of the message \lisp{}s1\rm{}.  Similarly, \lisp{}M3\rm{} overrides \lisp{}M4\rm{} as the implementation of message \lisp{}s2\rm{}.  Notice that the root class in the system, \lisp{}Object\rm{}, has no super class.  All classes in the system are subclasses of \lisp{}Object\rm{}, directly or indirectly.


\parshape 1    0pt  462pt {}


\sl{}Multiple Super Classes:\rm{}  Classes in LOOPS can have more than one class specified on their supers list.  Multiple super classes admit a modular programming style where (i) methods and associated variables for implementing a particular feature are placed in a single class and (ii) objects requiring combinations of independent features inherit them from multiple supers.  If \lisp{}D\rm{} had the supers list \lisp{}(E A)\rm{}, first the description from \lisp{}E\rm{} and its supers would be inherited, and then the description from \lisp{}A\rm{} and its supers.   In the simplest usage, the different features have unique variable names and selectors in each super.  In case of a name conflict, LOOPS uses a depth-first left to right precedence.  For example, if any super of \lisp{}E\rm{} had a method for \lisp{}s1\rm{}, then it would be used instead of the method \lisp{}M1\rm{} from \lisp{}A\rm{}.  In every case, inheritance from \lisp{}Object\rm{} (or any other {\lquotes}common{\rquotes} super class) is only considered after all other classes on the recursively defined supers list.  









\vskip10pt

\bf{}\noindent\save0\hbox{2.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Data Oriented Programming -- Using Active Values

\rm{}\penalty 2000
{\send1{(OVERVIEW.IM;4 10144 \count0)}}\penalty 2000
\mark{Data Oriented Programming -- Using Active Values}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(OVERVIEW.IM;4 10167 \count0)}}

In data oriented programming, one needs a way of specifying for any variable of an object whether any special procedure is to be invoked on read or write access, and if so which.  In LOOPS we check on every variable access whether the value is marked as an \sl{}active value\rm{}.  If so, the active value specifies the procedures to be invoked when the value of a variable (or property) is read or set.  This mechanism is dual to the notion of messages; messages are a way of telling objects to perform operations, which can change their variables as a side effect; active values are a way of accessing variables, which can send messages as a side effect.  The following notation for active values illustrates its three parts:



\lisp{}{\nofill{}{\char'43}(\arg{}localState\lisp{} \arg{}getFn\lisp{} \arg{}putFn\lisp{})\par}\rm{}



This notation is converted by a read macro into an instance of the LISP data type \lisp{}activeValue\rm{}.  The \arg{}localState\rm{} is a place for storing data.  The \arg{}getFn\rm{} and \arg{}putFn\rm{} are the names of functions that are applied with standard arguments when a program tries to get or put the value of a variable.  Every active value need not specify both a \arg{}getFn\rm{} and a \arg{}putFn\rm{}.  If the \arg{}getFn\rm{} is \lisp{}NIL\rm{}, then a get operation returns the local state.  If the \arg{}putFn\rm{} is \lisp{}NIL\rm{}, then a put operation replaces the local state.

Active values enable one process to monitor another one.  For example, we have developed a LOOPS debugging package that uses active values to trace and trap references to particular variables.  Another example is a graphics package that updates views of particular objects on a display when their variables are changed.  In both cases, the monitoring process is invisible to and isolated from the monitored process.  No changes to the code of the monitored object are necessary to enable monitoring.  

\sl{}Model{\char'57}View Controller Example:\rm{}  figure X.X shows an application of this to a simulation model.  Suppose that we want a program that simulates the flow of traffic in a city and displays selected parts of the simulation on a screen.  Active values enable us to divide the programming of this example into two parts: the traffic model and the view controller.  The traffic model consists of objects representing automobiles, traffic lights, emergency vehicles, and so on.  These objects exchange messages to simulate traffic interactions (e.g., when a traffic light turns green, it would send \lisp{}Move\rm{} messages to start cars moving).  The view controller provides windows into different parts of the city.  It contains information about how the objects are to be displayed.  We want a user to be able to move these windows around to change the view.




\vskip 10pt
{\send1{(OVERVIEW.IM;4 12917 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}(DEFINST Automobile-1 ...
   (InstanceVariables
      (position {\char'43}(Pos1 NIL UpdateDisplay) 
         displayObjects (DispObj1 DispObj2 DispObj3)
         doc (* position of car in traffic coordinate system))
      (speed 25))
   ...]\par}\rm{}




\parshape 1    0pt  462pt {}
\parshape 1   46pt  416pt {}Figure 3.   Instance of an automobile in a traffic simulation model.  Other classes describe such things as traffic lights, city blocks, and emergency vehicles.   Instances of these classes exchange messages while simulating the vehicles moving around in the model.  The instance variable \lisp{}position\rm{} is used to record the location of an automobile in the traffic coordinate system.  In this example, an active value in \lisp{}position\rm{} is used to update view objects that control pictures of the traffic patterns on an interactive display.  Whenever a simulation method puts a new value into the \lisp{}position\rm{} variable, the procedure \lisp{}UpdateDisplay\rm{} sends update messages to each object in a list of view objects.  These messages ultimately cause the graphics display to be updated.	      


\parshape 1    0pt  462pt {}


In figure X.X, there is an active value in the \lisp{}position\rm{} variable of an instance of \lisp{}Automobile\rm{}.  This active value is the interface between the object in the simulation model and the view controller.  Whenever a method in the simulation model changes the value of a \lisp{}position\rm{} variable, the procedure \lisp{}UpdateDisplay\rm{} in the \arg{}putFn\rm{} of the active value is invoked.  \lisp{}UpdateDisplay\rm{} updates the local value and sends a message to each of the view objects in the list stored as a property of \lisp{}position\rm{}.  These objects respond to a message by updating the view in the windows on the display screen.  The important point of this example is that it shows how the view controller can be invoked as a side effect of running the simulation.  The view can be changed without effecting any programs in the simulation model.  To change the set of simulation objects being monitored, only the interface to the view controller needs to be changed by adding active values.  The objects in the view controller may also be changed (e.g., to reflect changes to relative coordinates of the window and the traffic model).	









\vskip10pt

\bf{}\noindent\save0\hbox{2.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Knowledge Bases

\rm{}\penalty 2000
{\send1{(OVERVIEW.IM;4 15271 \count0)}}\penalty 2000
\mark{Knowledge Bases}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(OVERVIEW.IM;4 15296 \count0)}}

LOOPS was created to support a design environment in which there are community knowledge bases that people share, and to which they can add incremental updates.  We have chosen the term \sl{}knowledge base\rm{} instead of \sl{}data base\rm{} to emphasize the intended application of LOOPS to expert systems.  In expert systems, knowledge bases contain inference rules and heuristics for guiding problem solving.  This is in contrast to the tabular files of facts usually associated with data bases.    

\sl{}Knowledge Bases:\rm{}  Knowledge bases in LOOPS are files that are built up as a sequence of layers, where each layer contains changes to the information in previous layers.  A user can choose to get the most recent version of a knowledge base (that is, all of the layers) or any subset of layers.  The second option offers the flexibility of being able to share a community knowledge base without necessarily incorporating the most recent changes.  It also provides the capability of referring to or restoring any earlier version.  figure X.X illustrates this with an example.




\vskip 10pt
{\send1{(OVERVIEW.IM;4 16427 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}------------------------- Layer 1 -------------------------
Obj1 (x 4) ...
Obj2 (y 5) (w 3) ...
------------------------- Layer 2 -------------------------
Obj2 (y 7) (w 2) ...
Obj3 (z 6) ...
------------------------- Layer 3 -------------------------
Obj1 (x 8) ...
Obj4 (z 9) ...\par}\rm{}




\parshape 1    0
pt  462pt {}\parshape 1   46pt  416pt {}Figure 4.   Knowledge bases in LOOPS are files that are built-up incrementally as a sequence of layers.  Each layer contains updated descriptions of objects.  When a knowledge base is opened, the information in the later layers overrides the information in the earlier layers.  LOOPS makes it possible to select which layers will be used when a knowledge base is opened.  In this example, if the knowledge base is opened and only the first 2 layers are used, then \lisp{}Obj1\rm{} will have an \lisp{}x\rm{} variable with value \lisp{}4\rm{}.  If all three layers were connected, then the value would be \lisp{}8\rm{}.


\parshape 1    0pt  462pt {}


\sl{}Community Knowledge Bases:\rm{}  LOOPS partitions the process of updating a community knowledge base into two steps.  Any user of a community knowledge base can make tentative changes to a community knowledge base in his own (isolated) environment.  These changes can be saved in a layer of his personal knowledge base, and are marked as associated with the community knowledge base.  In a separate step, a data base manager can later copy such layers into a community knowledge base.  This separation of tasks is intended to encourage experimentation with proposed changes.  It separates the responsibility for exploring possibilities from the responsibility of maintaining consistent and standardized knowledge bases for shared use by a community.  The same mechanisms can be used by two individuals using personal knowledge bases to work on the same design.  They can conveniently exchange and compare layers that update portions of a design.        

\sl{}Unique Identifiers:\rm{}  The ability to determine when different layers are referring to the same entity is critical to the ability to share data bases.  To support this feature the LOOPS data base assigns unique identifiers (based on the computer's identification numbers, the date, and an unbounded count) to objects before they are written to a knowledge base.  This facility provides a grounding for more sophisticated notions of equality that might be desired in knowledge representation languages built on LOOPS.	 

\sl{}Environments:\rm{}{\send1{(OVERVIEW.IM;4 18858 \count0)}}  A user of LOOPS works in a personalized \sl{}environment\rm{}.  An environment provides a lookup table that associates unique identifiers with objects in the connected knowledge bases.  In an environment, user indicate dominance relationships between selected knowledge bases.  When an object is referenced through its unique identifier, the dominance relationships determine the order in which knowledge bases are examined to resolve the reference.  By making personal knowledge bases dominate over community knowledge bases, a user can override portions of community knowledge bases with his own knowledge bases.  

\sl{}Multiple Alternatives:\rm{}{\send1{(OVERVIEW.IM;4 19529 \count0)}}  An important use of environments is for providing speedy access to alternative versions (e.g., multiple alternatives in a design).  A user can have any number of environments available at the same time.  Each environment is fully isolated from the others.  Operations that move information between environments are always done explicitly through knowledge bases.



















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}CREATING AND USING OBJECTS

\rm{}\penalty 2000
{\send1{(OBJECTS.IM;5 84 \count0)}}\penalty 2000
\mark{CREATING AND USING OBJECTS}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(OBJECTS.IM;5 101 \count0)}}



In the LOOPS implementation of object-oriented programming, there are three types of objects:  Instances,{\send1{(OBJECTS.IM;5 281 \count0)}} Classes,{\send1{(OBJECTS.IM;5 305 \count0)}} and Metaclasses.{\send1{(OBJECTS.IM;5 341 \count0)}}  Instances are used like data objects in Lisp; they are commonly created, passed around, and modified by procedures (although all objects can be).  Classes and metaclasses are objects which {\lquotes}define{\rquotes} a group of objects that are {\lquotes}instances of{\rquotes} that class or metaclass.  The difference between classes and metaclasses is that the instances of a class are instances, and the instances of a metaclass are classes---all comments about classes apply to metaclasses, except where otherwise stated.



Note that the word {\lquotes}instance{\rquotes} is used in two separate ways:  the phrase {\lquotes}instance of{\rquotes} refers to the relation between any object and the class (or metaclass) that {\lquotes}defines{\rquotes} it.  The noun {\lquotes}instance{\rquotes} is only used to refer to those objects which are instances of classes.



A class contains information about instance variables,{\send1{(OBJECTS.IM;5 1426 \count0)}} class variables,{\send1{(OBJECTS.IM;5 1466 \count0)}} and methods.{\send1{(OBJECTS.IM;5 1494 \count0)}}  Instance variables are local variables stored within each instance of the class.  Class variables are variables stored within the class object, accessable from each instance of the class.  Methods are procedures which are used to perform operations on instances of the class.

Each Class also contains a list of other classes called {\lquotes}super classes{\rquotes}{\send1{(OBJECTS.IM;5 1865 \count0)}} or {\lquotes}supers{\rquotes}.{\send1{(OBJECTS.IM;5 1892 \count0)}}  The super class list provides a mechanism for inheriting instance variables, class variables, and methods from other classes (see page X.XX).


This section first describes how to create and use objects.  Next, {\lquotes}sending a message{\rquotes} (the standard way to invoke a method).  Next, creating and using new instances.  Next, defining and editing new classes.  Finally, defining a new method for a class.






\vskip10pt

\bf{}\noindent\save0\hbox{3.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Sending a Message to an Object

\rm{}\penalty 2000
{\send1{(OBJECTS.IM;5 2454 \count0)}}\penalty 2000
\mark{Sending a Message to an Object}
\penalty 2000
\vskip10pt
\penalty 2000
Operations in LOOPS are invoked by sending messages.  Sending a message to an object invokes a method (from the class that the object is an instance of) to execute the operation.  Messages are sent using the function \lisp{}{\char'137}\rm{} as follows:








\vskip 10pt
{\send1{(OBJECTS.IM;5 2795 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}object Selector arg\sub{1} $\cdots$ arg\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{NLambda NoSpread Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Sends the message \arg{}Selector\rm{} to the object \arg{}object\rm{} with the arguments \arg{}arg\sub{1}\rm{} $\cdots$ \arg{}arg\sub{N}\rm{}.  \arg{}Selector\rm{} is always implicitly quoted (i.e., not evaluated); the remaining arguments are evaluated.

\arg{}object\rm{} must be an {\lquotes}internal pointer{\rquotes} to the object.  The internal pointer to the object with the LOOPS name \lisp{}FOO\rm{} can be extracted by the form \lisp{}({\char'44} FOO)\rm{}.{\send1{(OBJECTS.IM;5 3209 \count0)}}

Note:  \lisp{}SEND\rm{}{\send1{(OBJECTS.IM;5 3242 \count0)}} can be used instead of \lisp{}{\char'137}\rm{}.  The arrow notation, although less mnemonic, is usually used to make expressions shorter and hence easier to type and read.

If it is necessary to \sl{}compute\rm{} the selector, one can use the function \lisp{}{\char'137}!\rm{},{\send1{(OBJECTS.IM;5 3491 \count0)}} which is just like \lisp{}{\char'137}\rm{} except that it also evaluates its \arg{}Selector\rm{} argument.



\parshape 1    0pt  462pt {}



Example:




\lisp{}{\nofill{}({\char'137} ({\char'44} PayRoll) PrintOut file1)\par}\rm{}



This sends a \lisp{}PrintOut\rm{} message to the class \lisp{}PayRoll\rm{} (with a single argument; the value of the Intrerlisp variable \lisp{}file1\rm{}).














\vskip10pt

\bf{}\noindent\save0\hbox{3.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Creating a New Instance

\rm{}\penalty 2000
{\send1{(OBJECTS.IM;5 4311 \count0)}}\penalty 2000
\mark{Creating a New Instance}
\penalty 2000
\vskip10pt
\penalty 2000
To create an instance of a particular class, one sends the message \lisp{}New\rm{}{\send1{(OBJECTS.IM;5 4411 \count0)}} to the class:



\vskip 10pt
{\send1{(OBJECTS.IM;5 4511 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}class\lisp{} New)\lisp{}\rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns a new instance of the class \arg{}class\rm{}.

In the usual case, initial values for instance variables are taken from the instance variable descriptions associated with the class.   LOOPS provides some other ways to exercise control over the initialization of values in instances (see page X.XX). 


\parshape 1    0pt  462pt {}









\vskip10pt

\bf{}\noindent\save0\hbox{3.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Naming and Pointing to Objects

\rm{}\penalty 2000
{\send1{(OBJECTS.IM;5 4966 \count0)}}\penalty 2000
\mark{Naming and Pointing to Objects}
\penalty 2000
\vskip10pt
\penalty 2000
In order to manipulate a LOOPS object, it is necessary to have a pointer to it.  One way to do this is to save a pointer to the object in an Interlisp variable, for example:



\lisp{}{\nofill{}(SETQ myVariable ({\char'137} ({\char'44} Transistor) New))\par}\rm{}



This creates a new instance of the \lisp{}Transistor\rm{} class, and stores a pointer to this instance in the Interlisp variable \lisp{}myVariable\rm{}.  Pointers to instances can also be saved in instance variables.  

LOOPS objects may be passed around and examined by Lisp functions.  The following function is useful:







\vskip 10pt
{\send1{(OBJECTS.IM;5 5545 \count0)}}\formatdef{462pt}{\lisp{}(Object? \arg{}X\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Returns \arg{}X\rm{} if it is a LOOPS objects, otherwise \lisp{}NIL\rm{}.


\parshape 1    0pt  462pt {}


Another way to manipulate an object is by giving it a unique {\lquotes}LOOPS name{\rquotes}.  An object can be given a LOOPS name by sending it the message \lisp{}SetName\rm{}




\vskip 10pt
{\send1{(OBJECTS.IM;5 5879 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}object\lisp{} SetName \arg{}name\lisp{})\lisp{}\rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Sets the LOOPS name \arg{}name\rm{} to refer to \arg{}object\rm{}.  LOOPS names are unique in a LOOPS environment; the name is assigned in the environment specified by the global variable \lisp{}CurrentEnvironment\rm{}{\send1{(OBJECTS.IM;5 6112 \count0)}} (see page X.XX for a complete description of environments).

If an attempt is made to assign a name already in use in the environment, and the global flag \lisp{}ErrorOnNameConflict\rm{}=\lisp{}T\rm{}, an error is generated.{\send1{(OBJECTS.IM;5 6379 \count0)}}  If \lisp{}ErrorOnNameConflict\rm{}=\lisp{}NIL\rm{}, and there is already an object \arg{}oldObject\rm{} with that name, the name is unset for \arg{}oldObject\rm{} and set for \arg{}object\rm{} without generating an error.


\parshape 1    0pt  462pt {}


For example, if \lisp{}I1\rm{} is an Interlisp variable whose value is a pointer to some instance, the object can be given the LOOPS name \lisp{}Foo\rm{} as follows:



\lisp{}{\nofill{}({\char'137} I1 SetName 'Foo)\par}\rm{}



After naming \lisp{}I1\rm{} this way, the user can refer to this object as \lisp{}({\char'44} Foo)\rm{},{\send1{(OBJECTS.IM;5 6868 \count0)}} which returns the object whose name is \lisp{}Foo\rm{}.

The user can refer to an object with a \sl{}computed\rm{} LOOPS name using the form \lisp{}({\char'44}! \arg{}EXPR\lisp{})\rm{}.{\send1{(OBJECTS.IM;5 7036 \count0)}}  For example, if the value of the lisp variable \lisp{}X\rm{} is the atom \lisp{}Apple\rm{}, then \lisp{}({\char'44}! X)\rm{} = \lisp{}({\char'44} Apple)\rm{}.


Classes having \lisp{}NamedObject\rm{}{\send1{(OBJECTS.IM;5 7221 \count0)}} (see page X.XX) as a super class inherit an instance variable, \lisp{}name\rm{}, that contains the name of the objects.  Instances of these classes can be named, as before, with a \lisp{}SetName\rm{} message, or alternatively as a side effect of setting the \lisp{}name\rm{} instance variable. 


Class objects are automatically given a LOOPS name when they are created, as described below.











\vskip10pt

\bf{}\noindent\save0\hbox{3.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Defining a New Class

\rm{}\penalty 2000
{\send1{(OBJECTS.IM;5 8355 \count0)}}\penalty 2000
\mark{Defining a New Class}
\penalty 2000
\vskip10pt
\penalty 2000
The way one creates a new class is to send the message \lisp{}New\rm{}{\send1{(OBJECTS.IM;5 8443 \count0)}} to a metaclass.  Usually, the metaclass named \lisp{}Class\rm{}{\send1{(OBJECTS.IM;5 8523 \count0)}} is used.



\vskip 10pt
{\send1{(OBJECTS.IM;5 8676 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}metaClass\lisp{} New \arg{}className\lisp{} \arg{}supersList\lisp{})\lisp{}\rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Returns a new instance of the metaclass \arg{}metaClass\rm{}.  \arg{}className\rm{} is the new class name and \arg{}supersList\rm{} is a list of the names of the super classes for this new class.  If the list of super class names is omitted, \arg{}supersList\rm{} defaults to \lisp{}(Object)\rm{}.


\parshape 1    0pt  462pt {}

Example:



\lisp{}{\nofill{}({\char'137} ({\char'44} Class) New 'StudentEmployee '(Student Employee))\par}\rm{}



This defines a new class, \lisp{}StudentEmployee\rm{} as a subclass of the known classes named \lisp{}Student\rm{} and \lisp{}Employee\rm{}.


An abbreviated way of defining a class is to use the function \lisp{}DC\rm{}:







\vskip 10pt
{\send1{(OBJECTS.IM;5 9281 \count0)}}\formatdef{462pt}{\lisp{}(DC \arg{}className supersList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent ({\lquotes}define class{\rquotes})  Sends the class \lisp{}Class\rm{} an appropriate \lisp{}New\rm{} message: 

\lisp{}({\char'137} ({\char'44} Class) \arg{}className\lisp{} \arg{}supersList\lisp{})\rm{}


\parshape 1    0
pt  462pt {}

Example:



\lisp{}{\nofill{}(DC 'StudentEmployee '(Student Employee))\par}\rm{}



This specifies that the class \lisp{}Student\rm{} is to be used recursively, inheriting both from \lisp{}Student\rm{} and all its supers, and from \lisp{}Employee\rm{} and all its supers.

After defining the class, one can modify its structure by editing the textual source for the class with \lisp{}EC\rm{}:







\vskip 10pt
{\send1{(OBJECTS.IM;5 9825 \count0)}}\formatdef{462pt}{\lisp{}(EC \arg{}className {---}\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent ({\lquotes}edit class{\rquotes})  \lisp{}EC\rm{} envokes the Interlisp editor on the textual source for the class named \arg{}className\rm{}.

The editor can also be envoked by sending the \lisp{}Edit\rm{} message:{\send1{(OBJECTS.IM;5 10027 \count0)}} \lisp{}({\char'137} ({\char'44} \arg{}className\lisp{}) Edit)\rm{}.


\parshape 1    0pt  462pt {}


For example, \lisp{}(EC 'StudentEmployee)\rm{} might start the editor editing the expression:



\lisp{}{\nofill{}[DEFCLASS StudentEmployee
	(MetaClass Class Edited: (* lc: "18-Oct-82 14:26"))
	(Supers Student Employee)
	(InstanceVariables)
	(Methods]\par}\rm{}



One can then change this to:



\lisp{}{\nofill{}[DEFCLASS StudentEmployee
	(MetaClass Class Edited: (* lc: "18-Oct-82 14:26"))
	(Supers Student Employee)
	(InstanceVariables
		(sponsor NIL doc (* Name of sponsor))
		(stay	3 doc (* number of months here)))
	(Methods]\par}\rm{}



Leaving the editor successfully at this point would install the two instance vararible descriptions in the class \lisp{}StudentEmployee\rm{}.  Then, in addition to those instance variables \lisp{}StudentEmployee\rm{} inherited from \lisp{}Student\rm{} and \lisp{}Employee\rm{}, each instance would also have two new ones, \lisp{}sponsor\rm{} and \lisp{}stay\rm{} with default values of \lisp{}NIL\rm{} and \lisp{}3\rm{} respectively.  A more extensive description of editing and changing classes is found in section X.XX.










\vskip10pt

\bf{}\noindent\save0\hbox{3.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Defining a Method

\rm{}\penalty 2000
{\send1{(OBJECTS.IM;5 11201 \count0)}}\penalty 2000
\mark{Defining a Method}
\penalty 2000
\vskip10pt
\penalty 2000
In order to define a method for a class, one can use the Interlisp function \lisp{}DM\rm{}:







\vskip 10pt
{\send1{(OBJECTS.IM;5 11355 \count0)}}\formatdef{462pt}{\lisp{}(DM \arg{}className selector argsOrFnName form\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Defines a method for the class named \arg{}className\rm{} that can be called using the selector \arg{}selector\rm{}.  If \arg{}form\rm{} is non-\lisp{}NIL\rm{}, then \arg{}argsOrFnName\rm{} is interpreted as the list of arguments for a function, and \arg{}form\rm{} as the body of that function.  If the first element of the list \arg{}argsOrFnName\rm{} is not \lisp{}self\rm{}, then \lisp{}self\rm{} is added on the front.  \lisp{}DM\rm{} defines a function whose name is the concatenation of \arg{}className\rm{}, a period, and \arg{}selector\rm{}.  For example, \lisp{}Class.List\rm{} is the function name created for the \lisp{}List\rm{} selector in the class \lisp{}Class\rm{}.  The function definition is created by substituting into \lisp{}(LAMBDA \arg{}argsOrFnName\lisp{} . \arg{}form\lisp{})\rm{}.

If \arg{}argsOrFnName\rm{} and \arg{}form\rm{} are \lisp{}NIL\rm{}, \lisp{}DM\rm{} creates a skeleton definition for the function and puts the user into the Interlisp editor, editing the skeleton.

If only \arg{}form\rm{} is \lisp{}NIL\rm{}, \arg{}argsOrFnName\rm{} is interpreted as the name of a function to be used for implementing the method.

Note:  a method can also be defined by sending the \lisp{}DefMethod\rm{}{\send1{(OBJECTS.IM;5 12474 \count0)}} message to the class:  \lisp{}({\char'137} \arg{}class\lisp{} DefMethod \arg{}selector\lisp{} \arg{}argsOrFnName\lisp{} \arg{}form\lisp{})\rm{}.



\parshape 1    0pt  462pt {}


Example: 



\lisp{}{\nofill{}(DM 'Number 'Increment '(self)
    '((* incr my IV) ({\char'137}{\char'100} :myValue (ADD1 ({\char'100} :myValue)))))\par}\rm{}



This defines a method with selector \lisp{}Increment\rm{} for the class \lisp{}Number\rm{} which adds 1 to the instance variable \lisp{}myValue\rm{} (the \lisp{}{\char'100}\rm{}-notation for accessing variables is described on page X.XX).  This form results in the definition of a function named \lisp{}Number.Increment\rm{} as follows:



\lisp{}{\nofill{}(DEFINEQ
   (Number.Increment 
      (LAMBDA (self)      (* incr my IV)
         ({\char'137}{\char'100} :myValue(ADD1 ({\char'100} :myValue)))]\par}\rm{}










\vskip 10pt
{\send1{(OBJECTS.IM;5 13202 \count0)}}\formatdef{462pt}{\lisp{}(EM \arg{}className selector {---}\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Calls the Interlisp editor to edit the method for the class named \arg{}className\rm{} associated with the selector \arg{}selector\rm{}.

Often it is more conveniently to use the LOOPS browser to edit the code for a method (see page X.XX).  


\parshape 1    0pt  462pt {}



Example:

To edit the method from the example above, one could type:



\lisp{}{\nofill{}(EM 'Number 'Increment)\par}\rm{}



This will edit the method of class \lisp{}Number\rm{} which responds to the selector \lisp{}Increment\rm{}, whether or not it has a name of the standard form.






















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}OBJECT VARIABLES AND PROPERTIES

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 96 \count0)}}\penalty 2000
\mark{OBJECT VARIABLES AND PROPERTIES}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(OBJECTVARS.IM;5 119 \count0)}}

There are two kinds of variables associated with an instance: its private \sl{}instance variables\rm{}{\send1{(OBJECTVARS.IM;5 244 \count0)}} and the \sl{}class variables\rm{}{\send1{(OBJECTVARS.IM;5 296 \count0)}} that it shares with all instances of the class.  This section deals with the functions for getting and putting values, and with a compact programming notation for referring to these variables from inside functions that implement methods.  In addition, there are properties which are associated with instance variables and class variables, with the methods of a class, and with classes themselves.  Given an object or a class, one can fetch or set any of these properties.  This section describes the functions for accessing all of these properties and values.







\vskip10pt

\bf{}\noindent\save0\hbox{4.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Access Expressions

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 1004 \count0)}}\penalty 2000
\mark{Access Expressions}
\penalty 2000
\vskip10pt
\penalty 2000
As mentioned above, there are a number of different types of variables and properties that can be associated with each class.  However, most of the accessing operations (getting and putting) in methods refer to the values or properties of instance variables or class variables of an instance.  LOOPS provides general functions (described later) for accessing these values, allowing variable names and property names to be computed.  However, most of the time the programmer knows the variable and property name to be used, and writing calls to these functions can be cumbersome.

Therefore, a simplified notation has been introduced for writing many common accessing operations, which is translated into calls to the appropriate functions:



\vskip 10pt
{\send1{(OBJECTVARS.IM;5 1789 \count0)}}\formatdef{462pt}{\lisp{}({\char'100} \arg{}object accessExpr\lisp{})\arg{}\lisp{}\rm{}}{Macro}

\penalty 2000\vskip-10pt\penalty 2000




\vskip 10pt
{\send1{(OBJECTVARS.IM;5 1830 \count0)}}\formatdef{462pt}{\lisp{}({\char'100} \arg{}accessExpr\lisp{})\arg{}\lisp{}\rm{}}{Macro}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Returns the variable or property value of the object \arg{}object\rm{} as specified by \arg{}accessExpr\rm{}.  Note that \arg{}accessExpr\rm{} is not evaluated; \arg{}object\rm{} is evaluated.

If only one argument is given to \lisp{}{\char'100}\rm{}, it is assumed that the object is bound to the variable \lisp{}self\rm{}.  This is very useful because by convention the first argument to any method is named \lisp{}self\rm{}.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(OBJECTVARS.IM;5 2268 \count0)}}\formatdef{462pt}{\lisp{}({\char'137}{\char'100} \arg{}object accessExpr newValue\lisp{})\arg{}\lisp{}\rm{}}{Macro}

\penalty 2000\vskip-10pt\penalty 2000




\vskip 10pt
{\send1{(OBJECTVARS.IM;5 2319 \count0)}}\formatdef{462pt}{\lisp{}({\char'137}{\char'100} \arg{}accessExpr newValue\lisp{})\arg{}\lisp{}\rm{}}{Macro}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Similar to \lisp{}{\char'100}\rm{}, sets the value of the variable or property specified by \arg{}accessExpr\rm{} (unevaluated) in the object \arg{}object\rm{} to \arg{}newValue\rm{}.  Returns \arg{}newValue\rm{}.  Note that \arg{}accessExpr\rm{} is not evaluated; the other arguments are evaluated.

Like \lisp{}{\char'100}\rm{}, if \arg{}object\rm{} is ommitted, it defaults to the value of the variable \lisp{}self\rm{}.


\parshape 1    0pt  462pt {}


Both \lisp{}{\char'100}\rm{} and \lisp{}{\char'137}{\char'100}\rm{} take the argument \arg{}accessExpr\rm{}, which is an {\lquotes}access expression{\rquotes}{\send1{(OBJECTVARS.IM;5 2804 \count0)}} which specifies exactly which variable or property value should be retrieved or set.  \arg{}accessExpr\rm{} is an atom which specifies a variable name, an optional property name, and whether the variable is an instance variable or a class variable.

Some examples:



\vskip 10pt
\vskip-10pt

\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}({\char'100} :FOO)\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Retrieve the value of instance variable \lisp{}FOO\rm{} (from the object that is the value of \lisp{}self\rm{}).


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}({\char'100} XX ::FOO)\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Retrieve the value of class variable \lisp{}FOO\rm{} (from the object that is the value of \lisp{}XX\rm{}).


\parshape 1    0
pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}({\char'137}{\char'100} ::FOO:,BAR 5)\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Store \lisp{}5\rm{} as the value of the \lisp{}BAR\rm{} property of class variable \lisp{}FOO\rm{} (of the object that is the value of \lisp{}self\rm{}).


\parshape 1    0pt  462pt {}















\vskip10pt

\bf{}\noindent\save0\hbox{4.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Getting Variable and Property Values

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 3955 \count0)}}\penalty 2000
\mark{Getting Variable and Property Values}
\penalty 2000
\vskip10pt
\penalty 2000
The functions \lisp{}GetValue\rm{} and \lisp{}GetClassValue\rm{} retrieve from an instance the values of variables or their properties.  If the value bound to an instance variable or class variable is an \sl{}active value\rm{}{\send1{(OBJECTVARS.IM;5 4185 \count0)}} with a \arg{}getFn\rm{}, then \lisp{}GetValue\rm{} and \lisp{}GetClassValue\rm{} of these functions trigger the \arg{}getFn\rm{} (see page X.XX).








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 4386 \count0)}}\formatdef{462pt}{\lisp{}(GetValue \arg{}object varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the value or property value of the instance variable \arg{}varName\rm{} in the object \arg{}object\rm{}.  Each instance of a class has its own separate set of instance variables.

If \arg{}propName\rm{} is \lisp{}NIL\rm{}, \lisp{}GetValue\rm{} returns the value of the variable.  In proper usage, \arg{}object\rm{} is an instance and the local value of the variable is returned.  If no local value has been set, \lisp{}GetValue\rm{} returns the default value from the class.  Since this is a common case, default values inherited from super classes of the class are cached in the class itself, thus avoiding a runtime search.

If \arg{}propName\rm{} is not \lisp{}NIL\rm{}, \lisp{}GetValue\rm{} returns the value associated with the property named  \arg{}propName\rm{} of the variable \arg{}varName\rm{}.  If none is found in the instance, it returns the default property value found in the class or one of its super classes.  If no property value is found in any of the super classes, the default value used is the value of the global variable \lisp{}NotSetValue\rm{}{\send1{(OBJECTVARS.IM;5 5414 \count0)}} (currently bound to \lisp{}?\rm{}).  Note: this is different from Interlisp, where if no value of a property is found, then \lisp{}NIL\rm{} is returned.

\lisp{}GetValue\rm{} fetches a value from an \sl{}instance\rm{} of a class.  It is an error to try to use \lisp{}GetValue\rm{} to fetch an instance variable from a class.   To fetch the default value of an instance variable from a class, use \lisp{}GetClassIV\rm{} (see page X.XX).



\parshape 1    0pt  462pt {}









\vskip 10pt
{\send1{(OBJECTVARS.IM;5 5899 \count0)}}\formatdef{462pt}{\lisp{}(GetClassValue \arg{}object varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the value (if \arg{}propName\rm{}=\lisp{}NIL\rm{}) or property value of the class variable \arg{}varName\rm{} for the class of the \arg{}object\rm{} (which may be either an instance or a class).

Class variables are inherited from the super classes.  If \arg{}object\rm{} is an instance, lookup begins at the class of \arg{}object\rm{} since instances do not have class variables stored locally.  If the class does not have a class variable \arg{}varName\rm{}, \lisp{}GetClassValue\rm{} searches through the super classes of the class until it finds \arg{}varName\rm{}.  Since this is thought to be an relatively rare in code, class variables are stored only in the class in which they are defined, and the runtime search is necessary. 

Conceptually, one should think of a class variable of a class as being shared by all instances of that class, and by all instances of any of its subclasses.  For example, suppose \lisp{}Transistor\rm{} is a class with class variable, \lisp{}TransSeqNum\rm{}, and \lisp{}DepletionTransistor\rm{} is a subclass of \lisp{}Transistor\rm{}.  Then setting the class variable \lisp{}TransSeqNum\rm{} from an instance of \lisp{}DepletionTransistor\rm{} would be seen by all instances of \lisp{}Transistor\rm{}.  


\parshape 1    0pt  462pt {}














\vskip10pt

\bf{}\noindent\save0\hbox{4.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Putting Variable Values and Property Values

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 8972 \count0)}}\penalty 2000
\mark{Putting Variable Values and Property Values}
\penalty 2000
\vskip10pt
\penalty 2000
\lisp{}PutValue\rm{} and \lisp{}PutClassValue\rm{} are functions used for storing variable or property values in an instance.  They are analogous to \lisp{}GetValue\rm{} and \lisp{}GetClassValue\rm{}; as with these functions, if the value of the variable or property is an active value{\send1{(OBJECTVARS.IM;5 9252 \count0)}} with a \arg{}putFn\rm{}, trying to store a value for that variable or property will invoke the \arg{}putFn\rm{} (see page X.XX).








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 9459 \count0)}}\formatdef{462pt}{\lisp{}(PutValue \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Stores \arg{}newValue\rm{} as the value or property value of the instance variable \arg{}varName\rm{} in the object \arg{}object\rm{}.  Returns \arg{}newValue\rm{}.

If \arg{}propName\rm{} is \lisp{}NIL\rm{}, \lisp{}PutValue\rm{} stores \arg{}newValue\rm{} as the value of \arg{}varName\rm{} in \arg{}object\rm{}.  If \arg{}propName\rm{} is non-\lisp{}NIL\rm{}, then \arg{}newValue\rm{} is stored as the value of the property \arg{}propName\rm{} of the instance variable \arg{}varName\rm{}.  

For example, \lisp{}(PutValue \arg{}pos\lisp{} 'X 0)\rm{}, stores \lisp{}0\rm{} as the value of the instance variable \lisp{}X\rm{} of the object \arg{}pos\rm{}.

\lisp{}PutValue\rm{} works for storing values in an instance of a class.  It is an error to try to store a default instance variable in a class with \lisp{}PutValue\rm{}.   To store the default value for an instance variable directly in the class, use \lisp{}PutClassIV\rm{} (see page X.XX).


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 10376 \count0)}}\formatdef{462pt}{\lisp{}(PutClassValue \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Similar to \lisp{}PutValue\rm{}, except it stores \arg{}newValue\rm{} as the value or property value of a class variable and property.  \arg{}object\rm{} may either be an instance or a class.  Returns \arg{}newValue\rm{}.

If \arg{}varName\rm{} is not local to the class, then the value will be put in the first class in the inheritance list that \arg{}varName\rm{} is found.


\parshape 1    0pt  462pt {}



The following functions push a value on the front of a list already stored in a variable:







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 10883 \count0)}}\formatdef{462pt}{\lisp{}(PushValue \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 10958 \count0)}}\formatdef{462pt}{\lisp{}(PushClassValue \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent \lisp{}PushValue\rm{} and \lisp{}PushClassValue\rm{} add \arg{}newValue\rm{} on the front of the list that is the value of the indicated variable or property, and store the result back in the variable or property.

These functions are defined so that if the value accessed is an active value, the \arg{}getFn\rm{} will be triggered when the old value of the list is fetched, and the \arg{}putFn\rm{} when the new value is stored back (see page X.XX).


\parshape 1    0pt  462pt {}



The following function adds a value on the end of an instance variable list:








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 11551 \count0)}}\formatdef{462pt}{\lisp{}(AddValue \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Similar to \lisp{}PushValue\rm{}, except that \arg{}newValue\rm{} is added to the \sl{}end\rm{} of the variable list.

There is no function for adding values to the end of class variable lists.


\parshape 1    0
pt  462pt {}


















\vskip10pt

\bf{}\noindent\save0\hbox{4.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Non-triggering Get and Put

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 13526 \count0)}}\penalty 2000
\mark{Non-triggering Get and Put}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(OBJECTVARS.IM;5 13547 \count0)}}




Using active values (page X.XX), it is possible to associate functions with a variable (or property) that will be called whenever the variable (or property) is read or set.  In some cases, it is useful to be able to access a value from an instance or class variable without triggering any active value which might be stored.  This can be done using the following functions:







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 14041 \count0)}}\formatdef{462pt}{\lisp{}(GetValueOnly \arg{}object varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 14110 \count0)}}\formatdef{462pt}{\lisp{}(GetClassValueOnly \arg{}object varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}GetValueOnly\rm{} and \lisp{}GetClassValueOnly\rm{} retrieve the value of instance variables and class variables, respectively, without triggering any active values.

\lisp{}GetValueOnly\rm{} retrieves the default value from the class if none exists in the instance.


\parshape 1    0pt  462pt {}


To store a value without triggering any active values, the following functions are provided:







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 14531 \count0)}}\formatdef{462pt}{\lisp{}(PutValueOnly \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 14609 \count0)}}\formatdef{462pt}{\lisp{}(PutClassValueOnly \arg{}object varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent These functions store \arg{}newValue\rm{} in the instance variable or class variable, without triggering any active values, and return \arg{}newValue\rm{}.



\parshape 1    0pt  462pt {}


Note that \lisp{}GetClassValueOnly\rm{} and \lisp{}PutClassValueOnly\rm{} can take either a class or an instance.  \lisp{}GetValueOnly\rm{} and \lisp{}PutValueOnly\rm{} will only take instances.









\vskip10pt

\bf{}\noindent\save0\hbox{4.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Local Get Functions

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 15041 \count0)}}\penalty 2000
\mark{Local Get Functions}
\penalty 2000
\vskip10pt
\penalty 2000
Sometimes it is desirable to find out if a value or property is set in a particular class or instance, without inheriting any information which is not local, and not activating any active values.  This can be done with the following functions:







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 15348 \count0)}}\formatdef{462pt}{\lisp{}(GetIVHere \arg{}object varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}object\rm{} must be an instance.  Returns the instance variable value that is found in the instance;  if none is found, then returns the value of the global variable \lisp{}NotSetValue\rm{}{\send1{(OBJECTVARS.IM;5 15556 \count0)}} (initially \lisp{}?\rm{}).




\parshape 1    0pt  462pt {}









\vskip 10pt
{\send1{(OBJECTVARS.IM;5 15833 \count0)}}\formatdef{462pt}{\lisp{}(GetCVHere \arg{}object varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent \arg{}object\rm{} must be a class.  Returns the class variable value that is found in the class;  if none is found, then returns the value of \lisp{}NotSetValue\rm{}.


\parshape 1    0pt  462pt {}

In both \lisp{}GetIVHere\rm{} and \lisp{}GetCVHere\rm{}, if the value is an active value, the actual active value is returned, without being triggered.


Note that there are no need to have special local put functions, since all put functions are local to the instance or class.  For local nontriggering storage functions, use \lisp{}PutValueOnly\rm{} and \lisp{}PutClassValueOnly\rm{} (page X.XX).









\vskip10pt

\bf{}\noindent\save0\hbox{4.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Accessing Class and Method Properties

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 16523 \count0)}}\penalty 2000
\mark{Accessing Class and Method Properties}
\penalty 2000
\vskip10pt
\penalty 2000
Most of the get and put functions described in the preceding sections work with instances, but not with classes.  Some exceptions are \lisp{}GetClassValue\rm{}, \lisp{}PutClassValue\rm{}, \lisp{}GetClassValueOnly\rm{}, and \lisp{}PutClassValueOnly\rm{}, which can take either an instance or a class, and access class variables, and \lisp{}GetCVHere\rm{} which takes a class.

The following functions access the \sl{}default\rm{} value or property value of an instance variable (which is stored in the class):







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 17055 \count0)}}\formatdef{462pt}{\lisp{}(GetClassIV \arg{}class varName propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the \sl{}default\rm{} value or property value of the instance variable \arg{}varName\rm{} in the class \arg{}class\rm{}.


\parshape 1    0pt  462pt {}







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 17243 \count0)}}\formatdef{462pt}{\lisp{}(PutClassIV \arg{}class varName newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Stores \arg{}newValue\rm{} as the \sl{}default\rm{} value or property value of the instance variable \arg{}varName\rm{} in the class \arg{}class\rm{}.  If \arg{}varName\rm{} is not local to the class, this will cause an error.  Returns \arg{}newValue\rm{}.


\parshape 1    0pt  462pt {}


Note:  \lisp{}GetClassIV\rm{} and \lisp{}PutClassIV\rm{} do not trigger active values (page X.XX).





LOOPS provides property list storage for classes themselves and for methods of classes.  A typical use of these properties is to document a class and its methods.  Like the put and get functions for variables, these functions can trigger active values.  The functions for class properties are:








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 17930 \count0)}}\formatdef{462pt}{\lisp{}(GetClass \arg{}class propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the value of the property \arg{}propName\rm{} of \arg{}class\rm{}.  If \arg{}propName\rm{} is \lisp{}NIL\rm{}, \lisp{}GetClass\rm{} returns the metaclass of \arg{}class\rm{}.

Class properties are inherited like class variables, so \lisp{}GetClass\rm{} will search through the super classes of \arg{}class\rm{} if \arg{}propName\rm{} is not found in \arg{}class\rm{} itself.


\parshape 1    0
pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 18324 \count0)}}\formatdef{462pt}{\lisp{}(PutClass \arg{}class newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Sets the value of the property \arg{}propName\rm{} of \arg{}class\rm{} to \arg{}newValue\rm{}.  If \arg{}propName\rm{} is \lisp{}NIL\rm{}, \lisp{}GetClass\rm{} sets the metaclass of \arg{}class\rm{} to \arg{}newValue\rm{}.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 18570 \count0)}}\formatdef{462pt}{\lisp{}(GetClassOnly \arg{}class propName {---}\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 18634 \count0)}}\formatdef{462pt}{\lisp{}(PutClassOnly \arg{}class newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent These functions are analogous to \lisp{}GetClass\rm{} and \lisp{}PutClass\rm{}, except that they never trigger active values.  



\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 18808 \count0)}}\formatdef{462pt}{\lisp{}(GetClassHere \arg{}class propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the local value of the property \arg{}propName\rm{} of \arg{}class\rm{}.  If \arg{}propName\rm{} is not found locally, \lisp{}GetClassHere\rm{} returns the value of the global variable \lisp{}NotSetValue\rm{}{\send1{(OBJECTVARS.IM;5 19020 \count0)}} (initially \lisp{}?\rm{}).


\parshape 1    0pt  462pt {}


The functions for accessing method properties are:







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 19160 \count0)}}\formatdef{462pt}{\lisp{}(GetMethod \arg{}class selector propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent If \arg{}propName\rm{} is \lisp{}NIL\rm{}, \lisp{}GetMethod\rm{} returns the method (Interlisp function name) which implements the message \arg{}selector\rm{} of the class \arg{}class\rm{}.  If \arg{}propName\rm{} is non-\lisp{}NIL\rm{}, it returns the value of the property \arg{}propName\rm{} of the method.

Method properties are inherited; the retrieval process involves searching through super classes of \arg{}class\rm{} if the property is not found in \arg{}class\rm{} itself.  


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 19669 \count0)}}\formatdef{462pt}{\lisp{}(PutMethod \arg{}class selector newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent If \arg{}propName\rm{} is \lisp{}NIL\rm{}, \lisp{}PutMethod\rm{} sets the method which implements the message \arg{}selector\rm{} of the class \arg{}class\rm{} to \arg{}newValue\rm{}.  If \arg{}propName\rm{} is non-\lisp{}NIL\rm{}, it sets the value of the property \arg{}propName\rm{} of the method to \arg{}newValue\rm{}.  Returns \arg{}newValue\rm{}.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 20031 \count0)}}\formatdef{462pt}{\lisp{}(GetMethodOnly \arg{}class selector propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 20105 \count0)}}\formatdef{462pt}{\lisp{}(PutMethodOnly \arg{}class selector newValue propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Analogous to \lisp{}GetMethod\rm{} and \lisp{}PutMethod\rm{} except that they never trigger active values.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 20268 \count0)}}\formatdef{462pt}{\lisp{}(GetMethodHere \arg{}class selector propName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the local value of the property \arg{}propName\rm{} the the method which implements the message \arg{}selector\rm{} of \arg{}class\rm{}.  If \arg{}propName\rm{} is not found locally, \lisp{}GetMethodHere\rm{} returns the value of the global variable \lisp{}NotSetValue\rm{}{\send1{(OBJECTVARS.IM;5 20540 \count0)}} (initially \lisp{}?\rm{}).


\parshape 1    0
pt  462pt {}


All of the above functions only work directly on classes, not on instances of those classes.  In addition, if a method or class variable is inherited, then the put functions change the property in the class in which the method or class variable is found in the supers list, not in the class which was the argument of the put function.









\vskip10pt

\bf{}\noindent\save0\hbox{4.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}General Get and Put Functions

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 21047 \count0)}}\penalty 2000
\mark{General Get and Put Functions}
\penalty 2000
\vskip10pt
\penalty 2000
The following functions are generalized get and put functions which accept a type argument and invoke the more specialized functions:







\vskip 10pt
{\send1{(OBJECTVARS.IM;5 21247 \count0)}}\formatdef{462pt}{\lisp{}(GetIt \arg{}object varOrSelector propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 21320 \count0)}}\formatdef{462pt}{\lisp{}(PutIt \arg{}object varOrSelector newValue propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 21388 \count0)}}\formatdef{462pt}{\lisp{}(GetItOnly \arg{}object varOrSelector propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 21465 \count0)}}\formatdef{462pt}{\lisp{}(PutItOnly \arg{}object varOrSelector newValue propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(OBJECTVARS.IM;5 21537 \count0)}}\formatdef{462pt}{\lisp{}(GetItHere \arg{}object varOrSelector propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent For all of these functions, the value of the \arg{}type\rm{} argument can be one of \lisp{}IV\rm{}, \lisp{}CV\rm{}, \lisp{}CLASS\rm{}, or \lisp{}METHOD\rm{} for instance variable, class variable, class, or method, respectively.  If \arg{}type\rm{} is \lisp{}NIL\rm{}, \lisp{}IV\rm{} is assumed.  The argument \arg{}varOrSelector\rm{} is interpreted as a variable name if \arg{}type\rm{} is \lisp{}IV\rm{} or \lisp{}CV\rm{}, a selector name if \arg{}type\rm{} is \lisp{}METHOD\rm{}, and is ignored if \arg{}type\rm{} is \lisp{}CLASS\rm{}.




\parshape 1    0pt  462pt {}

These functions are interpreted as follows:



\lisp{}{\nofill{}(GetIt $\cdots$ 'IV)  ==>  (GetValue $\cdots$)
(GetIt $\cdots$ 'CV)  ==>  (GetClassValue $\cdots$)
(GetIt $\cdots$ 'CLASS)  ==>  (GetClass $\cdots$)
(GetIt $\cdots$ 'METHOD)  ==>  (GetMethod $\cdots$)\par}\rm{}



The other functions are similar.

Note:  Actually, if \arg{}type\rm{}=\lisp{}IV\rm{}, these functions will call different functions depending on whether the object is a class or instance.










\vskip10pt

\bf{}\noindent\save0\hbox{4.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Summary of Get and Put Functions

\rm{}\penalty 2000
{\send1{(OBJECTVARS.IM;5 22672 \count0)}}\penalty 2000
\mark{Summary of Get and Put Functions}
\penalty 2000
\vskip10pt
\penalty 2000
In the following table, * indicates that no function is available.





\stretchyspaceskip{}\ragged 9999{}

\parshape 0 {}

\vskip 10pt
\hbox{\vbox{

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{}\cr\noalign{\hskip15pt}
\hbox par 104pt{Inherit{\char'57}Trigger}\cr\noalign{\hskip15pt}
\hbox par 104pt{Inherit{\char'57}DontTrigger}\cr\noalign{\hskip15pt}
\hbox par 104pt{Local{\char'57}DontTrigger}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{from instances:}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{Get{\char'57}Put fns for instance variables}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetValue\rm{} {\char'57} \lisp{}PutValue\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetValueOnly\rm{} {\char'57} \lisp{}PutValueOnly\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetIVHere\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{Get{\char'57}Put fns for class variables}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassValue\rm{} {\char'57} \lisp{}PutClassValue\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassValueOnly\rm{} {\char'57} \lisp{}PutClassValueOnly\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{*}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{from classes:}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{Get{\char'57}Put fns for instance variables}\cr\noalign{\hskip15pt}
\hbox par 104pt{*}\cr\noalign{\hskip15pt}
\hbox par 104pt{*}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassIV\rm{} {\char'57} \lisp{}PutClassIV\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{Get{\char'57}Put fns for class variables}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassValue\rm{} {\char'57} \lisp{}PutClassValue\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassValueOnly\rm{} {\char'57} \lisp{}PutClassValueOnly\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetCVHere\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{Get{\char'57}Put fns for class properties}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClass\rm{} {\char'57} \lisp{}PutClass\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassValueOnly\rm{} {\char'57} \lisp{}PutClassValueOnly\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetClassHere\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 0pt\valign{#\vfill\cr\hbox par 104pt{Get{\char'57}Put fns for method properties}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetMethod\rm{} {\char'57} \lisp{}PutMethod\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetMethodOnly\rm{} {\char'57} \lisp{}PutMethodOnly\rm{}}\cr\noalign{\hskip15pt}
\hbox par 104pt{\lisp{}GetMethodHere\rm{}}\cr\noalign{\hskip15pt}
}}}}

\ragged 0{}\normalspaceskip{}

\parshape 1    0pt  462pt {}




















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}ACTIVE VALUES

\rm{}\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 57 \count0)}}\penalty 2000
\mark{ACTIVE VALUES}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 77 \count0)}}

Active values provide a way of invoking procedures when the value of a variable (or property) is read or set.  This mechanism is dual to the notion of messages; messages are a way of telling objects to perform operations, which can change their variables as a side effect; active values are a way of accessing variables, which can send messages as a side effect.  This section presents the notation for creating active values.  Then, the concept of nested active values is introduced.  The nesting property enables many of the important applications of active values by supporting composition of the access functions.  Next is described how to use active values as the default values in a class, and how to share them.  Finally, the standard arguments to active value access functions are described, along with LOOPS functions that can be used in user-defined access functions.  




\vskip10pt

\bf{}\noindent\save0\hbox{5.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Active Values Notation

\rm{}\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 1035 \count0)}}\penalty 2000
\mark{Active Values Notation}
\penalty 2000
\vskip10pt
\penalty 2000
The notation for an active value illustrates its three parts:



\lisp{}{\nofill{}{\char'43}(\arg{}localState\lisp{} \arg{}getFn\lisp{} \arg{}putFn\lisp{})\par}\rm{}



This notation is converted by a read macro into an instance of the Interlisp data type \lisp{}activeValue\rm{}.  The \arg{}localState\rm{} field is used as a place for storing data.  The \arg{}getFn\rm{} and \arg{}putFn\rm{} are the names of functions that are applied with standard arguments when a program tries to get or put the value of a variable whose value is an active value.  Every active value need not specify both a \arg{}getFn\rm{} and a \arg{}putFn\rm{}.  If the \arg{}getFn\rm{} is \lisp{}NIL\rm{}, then a get operation returns the local state.  If the \arg{}putFn\rm{} is \lisp{}NIL\rm{}, then a put operation replaces the local state.









\vskip10pt

\bf{}\noindent\save0\hbox{5.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Nested Active Values

\rm{}\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 1869 \count0)}}\penalty 2000
\mark{Nested Active Values}
\penalty 2000
\vskip10pt
\penalty 2000
Often it is desirable to associate multiple access functions with a variable.  For example, we may want more than one process to monitor the state of some objects (e.g., a debugging process and a display process).  To preserve the isolation of these processes, it is important that they be able to work independently.  LOOPS uses nested active values as a way of composing these functions.	  

Nested active values are arranged so that the innermost active value is stored in the \arg{}localState\rm{} of the penultimate \arg{}localState\rm{}, and the outermost active value is the immediate value of the variable.  Put operations to a variable through such nested active values trigger the \arg{}putFn\rm{}s in sequence from the outermost to the innermost.  For example, suppose the variable tracing facility were used to trace access of the \lisp{}position\rm{} variable from the model{\char'57}view controller example (page X.XX).  The resulting active value would look like



\lisp{}{\nofill{}{\char'43}( {\char'43}(\arg{}Pos1\lisp{} NIL UpdateDisplay) GettingTracedVar SettingTracedVar)\par}\rm{}



An attempt to set the position variable would cause the function \lisp{}SettingTracedVar\rm{} to be called with the new value as one of its arguments.  \lisp{}SettingTracedVar\rm{} would operate and call the LOOPS function \lisp{}PutLocalState\rm{} to set its own \arg{}localState\rm{}.  This, in turn, would trigger the inner active value causing \lisp{}UpdateDisplay\rm{} to be invoked.	

Get operations work in the opposite order.  If there are three nested active values, a request to get the value will cause the innermost \arg{}getFn\rm{} (if any) to run, followed by the middle \arg{}getFn\rm{} (if any), followed by the outermost \arg{}getFn\rm{} (if any) whose value is returned by the get operation.  Each \arg{}getFn\rm{} sees only the value returned by the next nested \arg{}getFn\rm{}, and the innermost \arg{}getFn\rm{} sees the value stored in its localState.	   

LOOPS provides functions for embedding and removing active values from variables.  This idea of functional composition for nested active values is most appropriate when the order of composition does not matter.  We have resisted the development of other combinators for the functions using the same parsimony arguments that we used earlier about specializing and combining methods.  Just as inheritance from multiple super classes works most simply when the super classes describe independent features, active values work most simply when they interface between independent processes using simple functional composition.  Any more sophisticated control is seen as overloading the active value mechanism.  The escape for more complex cases is to combine the implicit access functions using Interlisp control structures to express the interactions.	









\vskip10pt

\bf{}\noindent\save0\hbox{5.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Active Values as Default Values

\rm{}\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 4729 \count0)}}\penalty 2000
\mark{Active Values as Default Values}
\penalty 2000
\vskip10pt
\penalty 2000
Suppose that \lisp{}I\rm{} is an instance of a class with an instance variable \lisp{}V\rm{}, whose default value is the active value \lisp{}A\rm{}.  Further suppose that the value of \lisp{}V\rm{} in the instance \lisp{}I\rm{} has never been set.  The first time \lisp{}(PutValue I V \arg{}exp\lisp{})\rm{} is invoked, a copy of \lisp{}A\rm{} is made.  This copy is inserted in the instance itself as the the value of the instance variable, with pointers to the same contents as \lisp{}A\rm{}.  Then the \arg{}putFn\rm{} is invoked, with the copy as the \arg{}activeVal\rm{} argument; this copy of \lisp{}A\rm{} provides a place where local state can be stored private to \lisp{}I\rm{}.

In some cases, one knows that the \arg{}putFn\rm{} will not actually write into the active value, and therefore the active value which is the default could be shared instead of needing to be copied.  To indicate this, the \arg{}localState\rm{} of \lisp{}A\rm{} should be made the atom \lisp{}Shared\rm{}.{\send1{(ACTIVEVALUES.IM;3 5656 \count0)}}  In the example below, the user knows that no change will be made in \lisp{}A\rm{} itself and thus uses a shared active value.

Example:  \lisp{}SUM\rm{} is a class with three instance variables, \lisp{}top\rm{}, \lisp{}bottom\rm{}, and \lisp{}sum\rm{}; \lisp{}top\rm{} and \lisp{}bottom\rm{} start with default values of \lisp{}0\rm{}, and \lisp{}sum\rm{} is to be computed when asked for.  One cannot update \lisp{}sum\rm{} independently.  



\lisp{}{\nofill{}[DEFCLASS SUM
	(MetaClass Class)
	(Supers Object)
	(InstanceVariables
		(top 0)
		(bottom 0)
		(sum {\char'43}(Shared ComputeSum NoUpdatePermitted))
	(ClassVariables)
	(Methods
		(printOn PrintColumn)]\par}\rm{}





The method for \lisp{}printOn\rm{} used in this example, and the \arg{}getFn\rm{}, \lisp{}ComputeSum\rm{}, and the \arg{}putFn\rm{}, \lisp{}NoUpdatePermitted\rm{}, are Lisp functions whose definitions are not shown here.  \lisp{}NoUpdatePermitted\rm{}{\send1{(ACTIVEVALUES.IM;3 6505 \count0)}} is available as part of the kernel.










\vskip10pt

\bf{}\noindent\save0\hbox{5.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Standard Access Functions

\rm{}\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 6673 \count0)}}\penalty 2000
\mark{Standard Access Functions}
\penalty 2000
\vskip10pt
\penalty 2000
LOOPS provides a convenient set of functions for some common applications.  For example, \lisp{}NoUpdatePermitted\rm{}, described in the example above, is used to stop update of the \arg{}localState\rm{} of an active value.   \lisp{}FirstFetch\rm{}{\send1{(ACTIVEVALUES.IM;3 6925 \count0)}} is a standard \arg{}getFn\rm{} that expects the \arg{}localState\rm{} of its active value to be an Interlisp expression to be evaluated; on the first fetch, the instance variable is set to the result of evaluating the expression.  This is illustrated in figure X.X, which shows a class \lisp{}TestDatum\rm{} that describes an instance variable \lisp{}sampleX\rm{}, to be computed on the first time that it is fetched, and then cached for future references.  At the time of activation of \lisp{}FirstFetch\rm{}, \lisp{}self\rm{} and \lisp{}varName\rm{} are bound to the instance and instance variable name in which the active value was found.   




\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 7577 \count0)}}
\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}(DEFCLASS TestDatum
	(MetaClass Class)
	(...
	(InstanceVariables (sampleX {\char'43}((RAND 0. 100.) FirstFetch)))...)\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 5.   Using an active value to compute and cache a value for a variable on the first fetch.


\parshape 1    0
pt  462pt {}


In some applications it is important to be able to access values indirectly from other instances.  For example, Steele [Steele80] has recommended this as approach for implementing equality constraints.  figure X.X shows a way of achieving this by using using the standard access functions \lisp{}GetIndirect\rm{} and \lisp{}PutIndirect\rm{}.  




\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 8217 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}(DEFINST JoeAsFatherPerspective ...
	(InstanceVariables
	   (age {\char'43}(({\char'43}{\char'44}JoeAsManPerspective age) GetIndirect PutIndirect))
	   ...\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 6.   Active values can be used to provide indirect access to values.  This is useful when it is desired for a variable in one instance to reflect the value of a variable stored elsewhere.  In this example, the instance \lisp{}{\char'43}{\char'44}JoeAsFatherPerspective\rm{} has an \lisp{}age\rm{} variable which always has the same value as the \lisp{}age\rm{} variable of the instance \lisp{}JoeAsManPerspective\rm{}.



\parshape 1    0pt  462pt {}


For some uses, the user may want to compute a default value if given, but replace the active value by the value given if the user sets the value of a variable.  For this the user can employ the system provided \arg{}putFn\rm{} of \lisp{}ReplaceMe\rm{},{\send1{(ACTIVEVALUES.IM;3 9029 \count0)}} as in:



\lisp{}{\nofill{}{\char'43}(NIL ComputeGoodValue ReplaceMe)\par}\rm{}



If this value is made the default in a class, then when a program tries to set this value, the instance will contain the value set.  However, if the user tried to fetch the value form this variable before setting it, the \arg{}getFn\rm{} \lisp{}ComputeGoodValue\rm{} would be invoked.  









\vskip10pt

\bf{}\noindent\save0\hbox{5.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}User-Defined Access Functions

\rm{}\penalty 2000
{\send1{(ACTIVEVALUES.IM;3 9493 \count0)}}\penalty 2000
\mark{User-Defined Access Functions}
\penalty 2000
\vskip10pt
\penalty 2000
The \arg{}getFn\rm{} and \arg{}putFn\rm{} of an active value are functions that are called with standard arguments:

\lisp{}(\arg{}self\lisp{} \arg{}varName\lisp{} \arg{}oldOrNewValue\lisp{} \arg{}propName\lisp{} \arg{}activeVal\lisp{} \arg{}type\lisp{})\rm{}

These arguments are interpreted as follows:



\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\arg{}self\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}The object containing this active value.

\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92
pt  370pt {}\save0\hbox{\arg{}varName\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}The name of the variable where this active value was stored.  This is \lisp{}NIL\rm{} if it is not stored in a variable.

\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\arg{}oldOrNewValue\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}For a \arg{}getFn\rm{}, this is the \arg{}localState\rm{} of the active value.  For a \arg{}putFn\rm{}, this is the new value to be stored in the active value.

\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt

\parshape 1   92pt  370pt {}\save0\hbox{\arg{}propName\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}The name of a property.  This is \lisp{}NIL\rm{} if the active value is not associated with the value of a property (i.e., if it is associated with the value of the variable itself).

\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\arg{}activeVal\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}The active value in which this \arg{}getFn\rm{} or \arg{}putFn\rm{} was found.

\parshape 1    0
pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\arg{}type\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}This specifies where the active value is stored;  \lisp{}NIL\rm{} means a instance variable, \lisp{}CV\rm{} means a class variable, \lisp{}CLASS\rm{} means a class property, or \lisp{}METHOD\rm{} means a method property.

\parshape 1    0pt  462pt {}


The value returned by the \arg{}getFn\rm{} is returned as the value of the get operation.


The \arg{}putFn\rm{} is expected to make any necessary changes to the \arg{}localState\rm{}.  This can be done using function \lisp{}PutLocalState\rm{} described below.  In changing the \arg{}localState\rm{}, embedded active values may be triggered.


Given an active value, the following functions can be used to retrieve or store its \arg{}localState\rm{}:







\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 11287 \count0)}}\formatdef{462pt}{\lisp{}(GetLocalState \arg{}activeValue self varName propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 11376 \count0)}}\formatdef{462pt}{\lisp{}(PutLocalState \arg{}activeValue newValue self varName propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}GetLocalState\rm{} returns the \arg{}localState\rm{} of the active value \arg{}activeValue\rm{}.  \lisp{}PutLocalState\rm{} stores \arg{}newValue\rm{} as the \arg{}localState\rm{} of the active value \arg{}activeValue\rm{}, and returns \arg{}newValue\rm{}.

Note that it is necessary to pass these functions the values for \arg{}self\rm{}, \arg{}varName\rm{}, \arg{}propName\rm{}, and \arg{}type\rm{}, in case any imbedded active values are triggered.



\parshape 1    0pt  462pt {}


If the \arg{}localState\rm{} of the active value is itself an active value, then it will be triggered to obtain the \arg{}localState\rm{} argument for the \arg{}getFn\rm{}.  For a \arg{}putFn\rm{}, an embedded active value will be triggered when the \arg{}putFn\rm{} calls \lisp{}PutLocalState\rm{}.  The following functions can be used to access the \arg{}localState\rm{} of an active value without triggering any embedded active values:








\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 12233 \count0)}}\formatdef{462pt}{\lisp{}(GetLocalStateOnly \arg{}activeValue\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 12299 \count0)}}\formatdef{462pt}{\lisp{}(PutLocalStateOnly \arg{}activeValue newValue\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}GetLocalStateOnly\rm{} returns the value of the \arg{}localState\rm{} of the active value \arg{}activeValue\rm{}.  \lisp{}PutLocalStateOnly\rm{} stores \arg{}newValue\rm{} as the \arg{}localState\rm{} of the active value \arg{}activeValue\rm{}, and returns \arg{}newValue\rm{}.  Both functions access the \arg{}localState\rm{} without triggering embedded active values.


\parshape 1    0pt  462pt {}


In some cases, it is important to be able to replace the entire active value expression by some quantity, independent of the depth of nesting of active values, without destroying the outer levels of nesting:







\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 12933 \count0)}}\formatdef{462pt}{\lisp{}(ReplaceActiveValue \arg{}activeVal newValue self varName propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent \lisp{}ReplaceActiveValue\rm{} overwrites \arg{}activeVal\rm{} whereever it is (either directly as the value or property of an instance variable, or as the local state of an embedded active value) with \arg{}newValue\rm{}

\lisp{}ReplaceActiveValue\rm{} searches the value (property) determined by its arguments until it finds \arg{}activeVal\rm{} in the nesting.  If \arg{}activeVal\rm{} is not found, an error is invoked.


\parshape 1    0pt  462pt {}


Example:  Suppose that we have a class \lisp{}RandomDatum\rm{} which describes an instance variable \lisp{}sampleX\rm{}, which we want to be computed as a random number on the first time that it is fetched, and then returned as a constant on all future fetches.  We could do this by defining the class as follows:



\lisp{}{\nofill{}(DEFCLASS RandomDatum
	(MetaClass Class)
	(...
	(InstanceVariables (sampleX {\char'43}(NIL SmashRandom ReplaceMe)))
	...)\par}\rm{}



where the function \lisp{}SmashRandom\rm{} is defined as follows:



\lisp{}{\nofill{}(LAMBDA (self varName value propName activeValue) 
	(ReplaceActiveValue activeValue (RAND 0. 100.) self varName]\par}\rm{}



On the first fetch of the value of \lisp{}sampleX\rm{} in any instance of \lisp{}RandomDatum\rm{}, the function \lisp{}SmashRandom\rm{} over-writes the active value with a random number.  This is a special case of the active value function \lisp{}FirstFetch\rm{} described earlier. 

The function \lisp{}MakeActiveValue\rm{} is used to make the value of some variable or property be an active value:







\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 14422 \count0)}}\formatdef{462pt}{\lisp{}(MakeActiveValue \arg{}self varOrSelector newGetFn newPutFn newLocalSt propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}self\rm{} is the object, \arg{}varName\rm{} is typically the name of a variable when the active value is being placed in an instance variable.  If the active value is being placed in a method, then \arg{}varName\rm{} should be bound to the selector name.  Active values can also be used for class variables, or properties of instance or class variables, or methods.  The interpretation of where to create the active value is determined by the argument \arg{}type\rm{}, which must be one of \lisp{}IV\rm{} (or \lisp{}NIL\rm{}), \lisp{}CV\rm{}, \lisp{}CLASS\rm{}, or \lisp{}METHOD\rm{}.

If \arg{}newLocalSt\rm{} = \lisp{}EMBED\rm{}, then a new active value is always created, containing as its \arg{}localState\rm{} whatever was found by \lisp{}GetItOnly\rm{} (page X.XX).   For other values of \arg{}newLocalSt\rm{}, an active value is created only if the current value is not an active value; otherwise the old one is simply updated with \arg{}newLocalSt\rm{}, \arg{}newGetFn\rm{}, and \arg{}newPutFn\rm{}.

If an old active value is being updated, then if \arg{}newGetFn\rm{} or \arg{}newPutFn\rm{} is \lisp{}NIL\rm{}, the old \arg{}getFn\rm{} or \arg{}putFn\rm{} is not overwritten.  If \arg{}newGetFn\rm{} or \arg{}newPutFn\rm{} is \lisp{}T\rm{}, the old \arg{}getFn\rm{} or \arg{}putFn\rm{} is reset to \lisp{}NIL\rm{}.






\parshape 1    0pt  462pt {}


The easiest way to define a function for use in active values is to use the function \lisp{}DefAVP\rm{}:







\vskip 10pt
{\send1{(ACTIVEVALUES.IM;3 15896 \count0)}}\formatdef{462pt}{\lisp{}(DefAVP \arg{}fnName putFlg\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent \lisp{}DefAVP\rm{} creates a template for defining an active value function and leaves the user in the Interlisp editor.  \arg{}fnName\rm{} will be the name of the function and \arg{}putFlg\rm{} is \lisp{}T\rm{} if this is to be a \arg{}putFn\rm{} and \lisp{}NIL\rm{} if it is to be a \arg{}getFn\rm{}.


\parshape 1    0pt  462pt {}


For \arg{}getFn\rm{}s, the template is



\lisp{}{\nofill{}[LAMBDA (self varName localSt propName activeVal type)
	(* This is a getFn for ...)
			localSt]\par}\rm{}




This template incorporates the standard arguments that a \arg{}getFn\rm{} receives, and the convention that they often return the value that is in their local state.

For \arg{}putFn\rm{}s, the template is



\lisp{}{\nofill{}[LAMBDA (self varName newValue propName activeVal type)
	(* This is a putFn for ...)
		(PutLocalState activeVal newValue self varName propName type)]\par}\rm{}



This template incorporates the standard arguments that a \arg{}putFn\rm{} receives, and the convention that they often put their resulting \arg{}newValue\rm{} in the \arg{}localState\rm{}.
















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}COMBINING INHERITED METHODS

\rm{}\penalty 2000
{\send1{(COMBININGMETHODS.IM;4 86 \count0)}}\penalty 2000
\mark{COMBINING INHERITED METHODS}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(COMBININGMETHODS.IM;4 106 \count0)}}




In practice, most methods used to manipulate LOOPS objects are inherited.  In the simplest examples of multiple inheritance, classes  represent independent features and there is no conflict between inherited methods.  However, when features inherited from classes interact, it is essential to be able to describe how to combine them.  Howard Cannon recognized this {\lquotes}mixing issue{\rquotes} as central in the design of Flavors:	



\vskip 10pt
\parshape 1   32pt  430pt {}{\lquotes}To restate the fundamental problem: there are several separate (orthogonal) \sl{}attributes\rm{} that an object wants to have; various \sl{}facets\rm{} of behavior (features) that want to be independently specified for an object.  For example, a window has a certain behavior as a rectangular area on a bit-mapped display.  It also has its behavior as a labeled thing, and as a bordered thing.  Each of these three behaviors is different, wants to be specified independently for each object, and is \sl{}essentially\rm{} orthogonal to the others.  It is this {\rquotes}essentially{\lquotes} that causes the trouble.{\rquotes}

{\lquotes}It is very easy to combine completely non-interacting behaviors.  Each would have its own set of messages, its own instance variables, and would never need to know about other objects with which it would be combined.  Either the multiple object or simple multiple superclass scheme could handle this perfectly.  The problem arises when it is necessary to have \sl{}modular\rm{} interactions between the orthogonal issues.  Though the label does not interact \sl{}strongly\rm{} with either the window or the border, it does have some minor interactions.  For example it wants to get redrawn when the window gets refreshed.  Handling these sorts of interactions is the Flavor system's main goal.{\rquotes}

... from [Cannon82]



\parshape 1    0
pt  462pt {}


This section considers cases where the inherited features interact, and describes some LOOPS facilities for combining interacting methods.  First, we describe a way of combining an inherited method with local method code.  Next, we describe other ways of combining methods inherited from multiple super classes.  Finally, we describe some special functions one can use to {\lquotes}escape{\rquotes} from the normal method inheritence conventions.




\vskip10pt

\bf{}\noindent\save0\hbox{6.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Augmenting an Inherited Method

\rm{}\penalty 2000
{\send1{(COMBININGMETHODS.IM;4 2515 \count0)}}\penalty 2000
\mark{Augmenting an Inherited Method}
\penalty 2000
\vskip10pt
\penalty 2000
The inheritance examples shown previously considered only cases where methods are inherited in toto.  In these examples, subclasses inherit a method or value unchanged, or they override it completely.  No mechanism was described that would enable a subclass to track changes in a method after it had been specialized in some way.

For combining an inherited method with local code, LOOPS provides the special method invocation \lisp{}{\char'137}Super\rm{}.







\vskip 10pt
{\send1{(COMBININGMETHODS.IM;4 3072 \count0)}}\formatdef{462pt}{\lisp{}({\char'137}Super \arg{}object selector arg\sub{1} $\cdots$ arg\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{NLambda NoSpread Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}object\rm{} is the object to which the method is applied (typically \lisp{}self\rm{}), \arg{}selector\rm{} is the selector for the method and \arg{}arg\sub{1}\rm{} $\cdots$ \arg{}arg\sub{N}\rm{} are the arguments for the method.  As with \lisp{}{\char'137}\rm{}, \arg{}selector\rm{} is not evaluated; the remaining arguments are evaluated.

\lisp{}{\char'137}Super\rm{} provides a form of relative addressing; it invokes the next more general method of the same name even when the specialized method invoking \lisp{}{\char'137}Super\rm{} is inherited over a distance.  An example of the use of \lisp{}{\char'137}Super\rm{} is given in figure X.X.

Note: \lisp{}SENDSUPER\rm{}{\send1{(COMBININGMETHODS.IM;4 3704 \count0)}} can be used instead of \lisp{}{\char'137}Super\rm{}.


\parshape 1    0pt  462pt {}





\vskip 10pt
{\send1{(COMBININGMETHODS.IM;4 3790 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}(BorderedWindow.Refresh
   [LAMBDA (self)         (* mjs: "11-JAN-82 19:28")

      (* * Method for refreshing a window that has a border)

                       (* First use the refresh method
                          inherited from Window.)
      ({\char'137}Super self Refresh)   
                       (* Then Re-display the border.)
      ({\char'137} ({\char'100} :border) Display)
      self])\par}\rm{}





\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 7.   This Interlisp procedure implements the \lisp{}Refresh\rm{} message for the class \lisp{}BorderedWindow\rm{}.  It uses \lisp{}{\char'137}Super\rm{} to invoke the more general method in the class \lisp{}Window\rm{}.  The object for the {\lquotes}border{\rquotes} of the bordered window is in the instance variable \lisp{}border\rm{}.  The specialized method returns the bordered window as its value.  In more complicated examples, calls to \lisp{}{\char'137}Super\rm{} and \lisp{}{\char'137}\rm{} can be combined using Interlisp iterative and conditional statements.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{6.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Combining Multiple Inherited Methods

\rm{}\penalty 2000
{\send1{(COMBININGMETHODS.IM;4 4878 \count0)}}\penalty 2000
\mark{Combining Multiple Inherited Methods}
\penalty 2000
\vskip10pt
\penalty 2000
Using \lisp{}{\char'137}Super\rm{}, a method can invoke the \sl{}single\rm{} next general method.  However, when a class has multiple super classes, sometimes it is necessary to invoke the general methods from \sl{}each\rm{} of the super classes.  In this situation, one can call \lisp{}{\char'137}SuperFringe\rm{}:








\vskip 10pt
{\send1{(COMBININGMETHODS.IM;4 5282 \count0)}}\formatdef{462pt}{\lisp{}({\char'137}SuperFringe \arg{}object selector arg\sub{1} $\cdots$ arg\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{NLambda NoSpread Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent This is similar to \lisp{}{\char'137}Super\rm{}, except that \lisp{}{\char'137}SuperFringe\rm{} invokes the next more general method of the same name for \sl{}each\rm{} of the super classes on the supers list of the class of the currently-executing method.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{6.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}General Method Invocation

\rm{}\penalty 2000
{\send1{(COMBININGMETHODS.IM;4 5640 \count0)}}\penalty 2000
\mark{General Method Invocation}
\penalty 2000
\vskip10pt
\penalty 2000
The functions \lisp{}{\char'137}Super\rm{} and \lisp{}{\char'137}SuperFringe\rm{} have proved to be sufficient for implementing most methods.  However, sometimes it is necessary to manipulate multiple inherited methods, and invoke them in some other order.  The following functions provide more general ways of invoking particular methods.  It is important to note that while these functions are more powerful than \lisp{}{\char'137}Super\rm{} or \lisp{}{\char'137}SuperFringe\rm{}, they are also more {\lquotes}dangerous{\rquotes}, in that they do not conform to the conventions of method inheritence.  These functions should only be used as a last resort when a method cannot be implemented in any other way.








\vskip 10pt
{\send1{(COMBININGMETHODS.IM;4 6387 \count0)}}\formatdef{462pt}{\lisp{}(DoMethod \arg{}object selectorExpr class arg\sub{1} $\cdots$ arg\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{NLambda NoSpread Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}DoMethod\rm{} allows computation of the name of the selector and the class from which that method should be found; it applies that method to \arg{}object\rm{}.

All the arguments to \lisp{}DoMethod\rm{} are evaluated; \arg{}selectorExpr\rm{} should evaluate to a selector name in the class computed from \arg{}class\rm{}.  If \arg{}class\rm{} is \lisp{}NIL\rm{}, then the class of \arg{}object\rm{} is used.  If no method for the computed selector is found in the computed class, an error is generated.  The remaining arguments, \arg{}arg\sub{1}\rm{} $\cdots$ \arg{}arg\sub{N}\rm{} are the arguments for the method.  


\parshape 1    0pt  462pt {}



In the case where the arguments to the method have already been evaluated, then one can use \lisp{}ApplyMethod\rm{} instead of \lisp{}DoMethod\rm{}:







\vskip 10pt
{\send1{(COMBININGMETHODS.IM;4 7171 \count0)}}\formatdef{462pt}{\lisp{}(ApplyMethod \arg{}object selector argList class\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent \arg{}argList\rm{} is a list of all the arguments to the method (except \arg{}object\rm{}) already evaluated.  The function applied is the one found by searching from \arg{}class\rm{}.  If \arg{}class\rm{} is \lisp{}NIL\rm{}, the class of \arg{}object\rm{} is used. 


\parshape 1    0pt  462pt {}









\vskip 10pt
{\send1{(COMBININGMETHODS.IM;4 7534 \count0)}}\formatdef{462pt}{\lisp{}(DoFringeMethods \arg{}object selectorExpr arg\sub{1} $\cdots$ arg\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{NLambda NoSpread Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Like \lisp{}DoMethod\rm{}, all of the arguments are evaluated.  \lisp{}DoFringeMethods\rm{} calls the method for \arg{}selectorExpr\rm{} in the class of \arg{}object\rm{}, if that method is defined in that class.  If the method is not defined in the class of \arg{}object\rm{}, the method of the same name for \sl{}each\rm{} of the super classes on the supers list of the class of \arg{}object\rm{} is envoked.


\parshape 1    0
pt  462pt {}


















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}INSTANCE CREATION

\rm{}\penalty 2000
{\send1{(INSTANCECREATION.IM;3 66 \count0)}}\penalty 2000
\mark{INSTANCE CREATION}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(INSTANCECREATION.IM;3 86 \count0)}}

The standard process of creating an instance of a class is to send a \lisp{}New\rm{} message to the class.  In the simplest case, this causes the information in the \sl{}instance variable descriptions\rm{} of the class to be used to establish default values for variables in the newly created instance.  When that process is finished, the instance can be altered in various ways by sending it messages.

LOOPS provides a variety of facilities for controlling this by using active values, standard access functions, and metaclasses.  This section summarizes some of the common cases.  See page X.XX for an illustratation of the use of these facilities to support the important example of composite objects. 




\vskip10pt

\bf{}\noindent\save0\hbox{7.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Specifying Values at Instance Creation

\rm{}\penalty 2000
{\send1{(INSTANCECREATION.IM;3 914 \count0)}}\penalty 2000
\mark{Specifying Values at Instance Creation}
\penalty 2000
\vskip10pt
\penalty 2000
The \lisp{}NewWithValues\rm{} message simplifies the case where it is desired to specify values and properties in an instance when it is created.  The form of this message is:



\vskip 10pt
{\send1{(INSTANCECREATION.IM;3 1236 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}class\lisp{} NewWithValues \arg{}valDescriptionList\lisp{})\lisp{}\rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}valDescriptionlist\rm{} must evaluate to a list of value descriptions, each of which is a list of a variable name, variable value, and properties; e.g.



\lisp{}{\nofill{}((\arg{}varName\sub{1}\lisp{} \arg{}value\sub{1}\lisp{} \arg{}prop\sub{1}\lisp{} \arg{}propVal\sub{1}\lisp{} $\cdots$)
 (\arg{}varName\sub{2}\lisp{} \arg{}value\sub{2}\lisp{} $\cdots$)
 $\cdots$)\par}\rm{}



The method for \lisp{}NewWithValues\rm{} first creates the object with \sl{}no\rm{} other initialization (e.g. without computing values specified in the class, as described in sections below).  It then directly installs the values and property lists specified in \arg{}valDescriptionList\rm{} and returns the created object.  Variables which have no description in \arg{}valDescriptionList\rm{} will be given no value in the instance, and thus will inherit the default value from the class.


\parshape 1    0pt  462pt {}









\vskip10pt

\bf{}\noindent\save0\hbox{7.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Sending a Message at Instance Creation

\rm{}\penalty 2000
{\send1{(INSTANCECREATION.IM;3 2200 \count0)}}\penalty 2000
\mark{Sending a Message at Instance Creation}
\penalty 2000
\vskip10pt
\penalty 2000
A simplification in form is available when one wants to send a message to an instance immediately after its creation.  For example, consider:



\lisp{}{\nofill{}({\char'137} ({\char'137} ({\char'44} Transistor) New) Display windowCenter)\par}\rm{}



which creates an instance of the \lisp{}Transistor\rm{} class, and then displays it at a point \lisp{}windowCenter\rm{}. A more compact notation for doing this is provided:



\lisp{}{\nofill{}({\char'137}New ({\char'44} Transistor) Display windowCenter)\par}\rm{}



where \lisp{}{\char'137}New\rm{}{\send1{(INSTANCECREATION.IM;3 2661 \count0)}} ({\lquotes}send New{\rquotes}) means to create a new instance and send it a message. The value returned by \lisp{}{\char'137}New\rm{} is the new instance.  Any value returned by the method is discarded.

In order to name an object, one can send the message \lisp{}SetName\rm{}{\send1{(INSTANCECREATION.IM;3 2925 \count0)}} to that object.  As a simplification, if one provides an argument to the \lisp{}New\rm{}{\send1{(INSTANCECREATION.IM;3 3030 \count0)}} message, the default interpretation of that argument is to use it as a name, sending the newly created object the \lisp{}SetName\rm{} message.  









\vskip10pt

\bf{}\noindent\save0\hbox{7.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Computing a Value at First Fetch

\rm{}\penalty 2000
{\send1{(INSTANCECREATION.IM;3 3322 \count0)}}\penalty 2000
\mark{Computing a Value at First Fetch}
\penalty 2000
\vskip10pt
\penalty 2000
As described earlier, one can use an active value to activate arbitrary procedures when values are fetched.  The built-in function \lisp{}FirstFetch\rm{}{\send1{(INSTANCECREATION.IM;3 3491 \count0)}} can be used as a \arg{}getFn\rm{} in an active value as the default value in the class.  If no value has been assigned to the variable or property before the value is fetched for the first time, the \lisp{}FirstFetch\rm{}{\send1{(INSTANCECREATION.IM;3 3736 \count0)}} active value is invoked.  

The local state of this active value can be a list which is a form to be evaluated.  During the evaluation, the variables \lisp{}self\rm{},{\send1{(INSTANCECREATION.IM;3 3914 \count0)}} \lisp{}varName\rm{},{\send1{(INSTANCECREATION.IM;3 3948 \count0)}} and \lisp{}propName\rm{}{\send1{(INSTANCECREATION.IM;3 3987 \count0)}} are are appropriately bound.  The local state of the \lisp{}FirstFetch\rm{} active value can also be an atom; if so, it is treated as the name of a function to be applied to the object, \lisp{}varName\rm{} and \lisp{}propName\rm{}.  The value of the form or function application is made the value in the instance as well as being returned as the value of the fetch. 

For example, the random number example could have been done as follows:



\lisp{}{\nofill{}(DEFCLASS TestDatum
	(MetaClass Class)
	(...
	(InstanceVariables (sampleX {\char'43}((RAND 0. 100.) FirstFetch)))
	...)\par}\rm{}



In this example \lisp{}FirstFetch\rm{} evaluates the form \lisp{}(RAND 0. 100.)\rm{} and replaces the value of the \lisp{}sampleX\rm{} variable of the instance by the random number.  In many cases the form may be a \lisp{}{\char'137}\rm{} expression.









\vskip10pt

\bf{}\noindent\save0\hbox{7.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Computing a Value at Instance Creation

\rm{}\penalty 2000
{\send1{(INSTANCECREATION.IM;3 4911 \count0)}}\penalty 2000
\mark{Computing a Value at Instance Creation}
\penalty 2000
\vskip10pt
\penalty 2000
In the previous example, \lisp{}FirstFetch\rm{} initializes the value of an instance variables at first access.  Sometimes it is important to initialize an instance variable when the instance is created.  For such cases LOOPS provides a distinguished \arg{}getFn\rm{}, \lisp{}AtCreation\rm{}.{\send1{(INSTANCECREATION.IM;3 5207 \count0)}}  If a default value of an instance variable or property contains an active value with \lisp{}AtCreation\rm{} as its \arg{}getFn\rm{}, then at creation time, the \arg{}localState\rm{} of this active value will be used to determine a value to be inserted in the new instance. 

As with \lisp{}FirstFetch\rm{}, if the \arg{}localState\rm{} is an atom, then it will be treated as the name of a function to be applied to the object, variable name, and property name.  If it is a list, then that list will be evaluated in a context in which \lisp{}self\rm{},{\send1{(INSTANCECREATION.IM;3 5741 \count0)}} \lisp{}varName\rm{},{\send1{(INSTANCECREATION.IM;3 5775 \count0)}} and \lisp{}propName\rm{}{\send1{(INSTANCECREATION.IM;3 5814 \count0)}} are appropriately bound.  Functions run at initialization time are run in the order in which they appear in the class.  Default values of variables are available to these functions.

If an object is created by \lisp{}NewWithValues\rm{}{\send1{(INSTANCECREATION.IM;3 6076 \count0)}} without a value being supplied for a variable which contains an \lisp{}AtCreation\rm{} default value, then at the first fetch of that variable, the function or form will be evaluated.  

Example:

Suppose we want to have an instance variable called \lisp{}creationDate\rm{} which tells the date that an instance was created.  This can be implemented in LOOPS as follows:



\lisp{}{\nofill{}(DEFCLASS DatedObject
	(MetaClass Class)
	(...
	(InstanceVariables (creationDate {\char'43}((DATE) AtCreation)))
	...)\par}\rm{}



The function \lisp{}DATE\rm{} in Interlisp computes a string which is the current date and time.  The value of this string at instance creation time is made the intitial value of \lisp{}creationDate\rm{}.

Another use of an \lisp{}AtCreation\rm{} active value might be to make an index entry to a newly created object. 









\vskip10pt

\bf{}\noindent\save0\hbox{7.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Special Actions at Instance Creation

\rm{}\penalty 2000
{\send1{(INSTANCECREATION.IM;3 7019 \count0)}}\penalty 2000
\mark{Special Actions at Instance Creation}
\penalty 2000
\vskip10pt
\penalty 2000
For some special cases, the user may want to have more control over the creation of instances.  For example, LOOPS itself uses different LISP data types to represent classes and instances.  The \lisp{}New\rm{}{\send1{(INSTANCECREATION.IM;3 7246 \count0)}} message for classes is fielded by their metaclass, usually the object \lisp{}MetaClass\rm{}. This section shows how to create a new metaclass.

Any metaclass should have \lisp{}Class\rm{} as one of its super classes and \lisp{}MetaClass\rm{}{\send1{(INSTANCECREATION.IM;3 7502 \count0)}} as its metaclass.  The easiest way to create a new metaclass is to send a \lisp{}New\rm{} message to \lisp{}MetaClass\rm{} as follows:



\lisp{}{\nofill{}({\char'137} ({\char'44} MetaClass) New \arg{}metaClassName\lisp{} \arg{}supers\lisp{})\par}\rm{}



This creates a new metaclass with the name \arg{}metaClassName\rm{} and with the super classes named in the list \arg{}supers\rm{}.  The default supers for metaclasses is the list containing \lisp{}Class\rm{}.  The metaclass for the the new class is \lisp{}MetaClass\rm{}.  

One then installs the specialized method for \lisp{}New\rm{} in the new metaclass.  This method provides the mechanism for creations of instances of the class which have this as a metaclass.  Sending this metaclass the message \lisp{}New\rm{} will cause the creation of a class with the appropriate property.  

As a simple example we will define a new metaclass \lisp{}ListMetaClass\rm{} which will augment the instance creation process by keeping a list of all instances which have been created.  This list will be kept on the class property \lisp{}allInstances\rm{}.  To create this class we go through the scenario in figure X.X.




\vskip 10pt
{\send1{(INSTANCECREATION.IM;3 8617 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}{\char'137} ({\char'137} ({\char'44} MetaClass) New 'ListMetaClass '(Class))
{\char'43}{\char'44}ListMetaClass       \sl{}--  We have now defined a new metaclass\lisp{}

                      \sl{}--  This defines the New method for that metaclass\lisp{}
{\char'137} (DM 'ListMetaClass 'New '(self name)
    '((* Create an instance and add it to list in class)
      (PROG ((newObj ({\char'137}Super self New name)))
                 (* newObj created by super method from class)
         (PutClass
            self
            (CONS newObj
                  (LISTP (GetClassHere self 'AllInstances)))
            'AllInstances)
                 (* LISTP returns previous list or NIL if none)
         (RETURN newObj]   
ListMetaClass.New

{\char'137} ({\char'137} ({\char'44} ListMetaClass) New 'Book)
{\char'43}{\char'44}Book                \sl{}-- This creates a new class ({\char'44} Book)\lisp{}
                      \sl{}whose metaclass is ({\char'44} ListMetaClass)\lisp{}
{\char'137} ({\char'137} ({\char'44} Book) New 'B1)
{\char'43}{\char'44}B1                  \sl{}-- Creating {\char'43}{\char'44}B1 using ListMetaClass.New\lisp{}
{\char'137} ({\char'137} ({\char'44} Book) New 'B2)
{\char'43}{\char'44}B2
{\char'137} (GetClass ({\char'44} Book) 'AllInstances)
({\char'43}{\char'44}B1 {\char'43}{\char'44}B2)           \sl{}-- The list of instances created so far.\lisp{}\par}\rm{}





\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 8.   In this scenario, a new metaclass \lisp{}ListMetaClass\rm{} is defined by the \lisp{}New\rm{} method of \lisp{}({\char'44} MetaClass)\rm{}.  It has metaclass \lisp{}({\char'44} MetaClass)\rm{}.  We then define the specialized \lisp{}New\rm{} method for \lisp{}ListMetaClass\rm{}.  This includes a call to its super (\lisp{}Class\rm{}) to actually create the object; it puts the newly created object on its list of objects.  We then create \lisp{}({\char'44} Book)\rm{} which has \lisp{}ListMetaClass\rm{} as its metaclass.  When two instances of book are created, each is placed on the list \lisp{}AllInstances\rm{} which is a class property.


\parshape 1    0pt  462pt {}
















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}COMPOSITE OBJECTS

\rm{}\penalty 2000
{\send1{(COMPOSITEOBJECTS.IM;2 66 \count0)}}\penalty 2000
\mark{COMPOSITE OBJECTS}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(COMPOSITEOBJECTS.IM;2 90 \count0)}}

LOOPS extends the notion of objects to make it recursive under composition, so that one can instantiate a group of related objects as an entity.  This is especially useful when relative relationships between members of the group must be isomorphic (but not equal) for distinct instances of the group.  The implementation of composite objects combines many of the programming features described above.  In particular, it is an application of the notion of metaclass. 




\vskip10pt

\bf{}\noindent\save0\hbox{8.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Basic Concepts for Composite Objects

\rm{}\penalty 2000
{\send1{(COMPOSITEOBJECTS.IM;2 663 \count0)}}\penalty 2000
\mark{Basic Concepts for Composite Objects}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}Parameters and Constants:\rm{}  LOOPS supports the use of structural templates to describe composite objects having a fixed set of parts.  Composite objects are normal LOOPS objects, created by an instantiation process and describable in the class inheritance network.  This contrasts with the idea of using for templates data structures that are merely \sl{}copied\rm{} to yield composite objects.  A primary benefit of making composite objects be classes is the ability to create slightly modified versions of a template by making a new subclass which inherits most of the structure of its super.  

\sl{}Creating a Template:\rm{}  To describe a composite object, one creates a class whose metaclass is \lisp{}Template\rm{}.{\send1{(COMPOSITEOBJECTS.IM;2 1412 \count0)}}  One can also use a metaclass one of whose supers is \lisp{}Template\rm{}.   Any class whose metaclass is \lisp{}Template\rm{} or one of its subclasses is called a template.  In a template, the default values for instance variables can point to other templates;  these will be treated as \sl{}parameters\rm{} and will be recursively instantiated when the parent template is instantiated.  All non-template classes and any other default values are treated as \sl{}constants\rm{} that are simply inherited by instances.  	  

\sl{}Instantiation:\rm{}  Instances of a template are created by sending it a \lisp{}New\rm{} message.  The instantiation process is recursive through all of the parameters of a template.  Every parameter is instantiated when it is first encountered.  Multiple references to the same parameter are always replaced by references to the same instantiated instance.  The instantiated composite object that is created is isomorphic to the original template structure with constants inherited and with distinct instances substituted for distinct templates (parameters).  Parameters in lists or active values are found and the containing structure is copied with appropriate substitutions.  If a composite object needs multiple distinct instances of the same type (e.g., two inverters), then multiple templates are needed in the description.	

\sl{}Example:\rm{}  figure X.X shows an example from digital design - a composite object for \lisp{}BitAmplifier\rm{} that is composed of two series-connected inverters.  The input of the first inverter is the input of the amplifier, the output of the first inverter is connected to the input of the second inverter, and the output of the second inverter is the output of the amplifier.  Different instantiations of \lisp{}BitAmplifier\rm{} contain distinct inverters connected in the same relative way.  This example also shows a possible use of active values in templates.  The containing composite object is set up so that its \sl{}output\rm{} instance variable uses an active value to track the value of the output variable of the second inverter.




\vskip 10pt
{\send1{(COMPOSITEOBJECTS.IM;2 3526 \count0)}}\parshape 1   46
pt  416pt {}

\lisp{}{\nofill{}[DEFCLASS BitAmplifier
   (MetaClass Template doc
      (* * Composite object template for an amplifer
           made of two series connected inverters.))
   (Supers Amplifier)
   (ClassVariables)
   (InstanceVariables
      (inputTerminal ({\char'44} Inverter1))
      (output {\char'43}( (({\char'44} Inverter2) output) GetIndirect PutIndirect)
         doc (* Data is stored and fetched from the variable
                 output in the instance of Inverter2))
   (Methods)]

[DEFCLASS Inverter1
   (MetaClass Template partOf ({\char'44} BitAmplifier) 
         doc (* Instance variable Input is inherited from Inverter))
   (Supers Inverter)
   (ClassVariables)
   (InstanceVariables
      (output ({\char'44} Inverter2)
         doc (* Output connected to second inverter)))
   (Methods)]

(DEFCLASS Inverter2
   (MetaClass Template partOf ({\char'44} BitAmplifier) )
   (Supers Inverter)
   (ClassVariables)
   (InstanceVariables
      (input ({\char'44} Inverter1)
         doc (* Input connected to first inverter)))
   (Methods)]\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 9.   Composite object templates for a \lisp{}BitAmplifier\rm{}. When instances are made, they will have distinct instances of the two inverters, with their input and output interconnected.  The instantiation process must be able to reach (possibly indirectly) all of the parts starting from the class to which the \lisp{}New\rm{} message is sent.  In this case, \lisp{}Inverter1\rm{} and \lisp{}Inverter2\rm{} are both mentioned in \lisp{}BitAmplifier\rm{}.  The example also illustrates the use of active values to provide indirect variable access in LOOPS.  In this example, the active value enables the output variable of an instance of \lisp{}BitAmplifier\rm{} to track the corresponding output variable of an instance of \lisp{}Inverter2\rm{} in the same composite object.


\parshape 1    0pt  462pt {}









\vskip10pt

\bf{}\noindent\save0\hbox{8.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Specializing Composite Objects

\rm{}\penalty 2000
{\send1{(COMPOSITEOBJECTS.IM;2 5441 \count0)}}\penalty 2000
\mark{Specializing Composite Objects}
\penalty 2000
\vskip10pt
\penalty 2000
Because the templates are classes, all of the power of the inheritance network is automatically available for describing and specializing composite objects.  To make this convenient, one can send the message \lisp{}Specialize\rm{}{\send1{(COMPOSITEOBJECTS.IM;2 5696 \count0)}} to any template form.  For example:



\lisp{}{\nofill{}({\char'137} ({\char'44} BitAmplifier) Specialize)\par}\rm{}



This creates a new set of templates such that each template in the new set is a specialization of a template in the old set.  One can then selectively edit the templates describing the new composite object.  In particular, one may want to change the names of the generated classes by sending them the message \lisp{}SetName\rm{}.{\send1{(COMPOSITEOBJECTS.IM;2 6127 \count0)}}  Unchanged portions of the template structure will continue to inherit values from the parent composite object.  A user can specialize a template by overriding instance variables.  To add parameters, one creates references to new templates.  Conversely, one can make a parameter into a constant by overriding an inherited variable value with a non-template in a subclass.	










\vskip10pt

\bf{}\noindent\save0\hbox{8.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Conditional and Iterative Templates

\rm{}\penalty 2000
{\send1{(COMPOSITEOBJECTS.IM;2 6651 \count0)}}\penalty 2000
\mark{Conditional and Iterative Templates}
\penalty 2000
\vskip10pt
\penalty 2000
Because the templates are fixed, they are not a sufficient mechanism for describing the instantiation of composite objects having conditional or repetitive parts.  Consistent with our stand on control mechanisms, we have not added \sl{}conditional\rm{} or \sl{}iterative structural descriptions\rm{} to LOOPS, but use available Interlisp control structures in methods.  For these cases, a user defines a new metaclass for the composite object.  (Recall that metaclasses are classes whose instances are classes.)  The metaclasses for templates should be subclasses of the distinguished metaclass \lisp{}Template\rm{}. The specialized metaclass should have a \lisp{}New\rm{} method that performs the conditional and iterative steps in the instantiation.  This approach works well in conjunction with the LOOPS mechanisms for specializing classes and methods.  For example, the specialized \lisp{}New\rm{} method can use \lisp{}{\char'137}Super\rm{} to access the standard code for the template-directed portion of the instantiation process.  figure X.X shows an example of a LOOPS template for a ring oscillator.  This composite object is made of a loop of serially connected inverters.




\vskip 10pt
{\send1{(COMPOSITEOBJECTS.IM;2 7865 \count0)}}
\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}(MetaRingOscillator.New
   [LAMBDA (self assocList numStages)    (* mjs: "11-JAN-82 19:28")
               (* * Procedure for creating a ring oscillator.)

   (PROG (ringOscillator firstInverter lastInverter inv1)
                                (* Create the inverter chain.)
      (SETQ inv1 (SETQ firstInverter ({\char'137} ({\char'44} Inverter) New)))
      [for i to (SUB1 numStages)
        do (SETQ lastInverter ({\char'137} ({\char'44} Inverter) New))
           ({\char'137} inv1 Connect lastInverter)
           (SETQ inv1 lastInverter]
                                (* Close the loop)   
      ({\char'137} lastInverter Connect firstInverter)
                                (* Make the ringOscillator object.)
      (SETQ ringOscillator ({\char'137}Super self New assocList))
               (* * the assocList here is the pairing
                    of Template classes found in the
                    instantiation of a template so far)
      ({\char'100}{\char'137} (ringOscillator input) firstInverter)
      ({\char'100}{\char'137} (ringOscillator output) lastInverter)
      (RETURN ringOscillator) ])\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 10.   Example of an iteratively specified composite object, a ring oscillator.  The ring oscillator is composed of a series of inverters serially-connected to form a loop.  To specify the iteration and interconnection of the inverters, a \lisp{}New\rm{} method is defined for the metaclass \lisp{}MetaRingOscillator\rm{}.  The Interlisp function for this method (\lisp{}MetaRingOscillator.New\rm{}) uses \lisp{}{\char'137}Super\rm{} to perform the template-driven part of the instantiation, that is, instantiating the ring oscillator object itself.  In this case, the template-driven portion of the instantiation is trivial, but the example shows how it can be combined generally with the procedural description.  \lisp{}MetaRingOscillator.New\rm{} uses iterative statements to make an instance of \lisp{}Inverter\rm{} for each stage of the oscillator.  After connecting the components together, it returns the ring oscillator object.	


\parshape 1    0
pt  462pt {}



















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{9}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}LOOPS KNOWLEDGE BASES

\rm{}\penalty 2000
{\send1{(KB.IM;2 74 \count0)}}\penalty 2000
\mark{LOOPS KNOWLEDGE BASES}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(KB.IM;2 99 \count0)}}

Loops was created to support a design environment in which there are community knowledge bases that people share, and to which they can add incremental updates.  This section describes our goals for this facility, the concepts that we have employed, and scenarios for using knowledge bases in Loops.

We have chosen the term knowledge base instead of data base to emphasize two things: the kind of information being stored and constraints on the amount of information.  Loops will be used mainly for expert system applications where relatively modest amounts of information are used for guiding reasoning.  This information (i.e., knowledge) consists of inference rules and heuristics for guiding problem solving.  This is in contrast to potentially enormous files of facts, for example, social security records for California.  Reflecting this difference of scale, we have optimized the implementation to support fast access and updating to a smaller amount of information which is expected to fit in main memory for any one session.  For example, we maintain an index to the object information in computer memory.







\vskip10pt

\bf{}\noindent\save0\hbox{9.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Review of Knowledge Base Concepts

\rm{}\penalty 2000
{\send1{(USINGKBSUB1.IM;4 99 \count0)}}\penalty 2000
\mark{Review of Knowledge Base Concepts}
\penalty 2000
\vskip10pt
\penalty 2000



{\send1{(USINGKBSUB1.IM;4 270 \count0)}}

\sl{}Knowledge Bases:\rm{}  Knowledge bases in LOOPS are files that are built up as a sequence of layers, where each layer contains changes to the information in previous layers.  A user can choose to get the most recent version of a knowledge base (that is, all of the layers) or any subset of layers.  The second option offers the flexibility of being able to share a community knowledge base without necessarily incorporating the most recent changes.  It also provides the capability of referring to or restoring any earlier version.  figure X.X illustrates this with an example.




\vskip 10pt
{\send1{(USINGKBSUB1.IM;4 909 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}------------------------- Layer 1 -------------------------
Obj1 (x 4) ...
Obj2 (y 5) (w 3) ...
------------------------- Layer 2 -------------------------
Obj2 (y 7) (w 2) ...
Obj3 (z 6) ...
------------------------- Layer 3 -------------------------
Obj1 (x 8) ...
Obj4 (z 9) ...\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 11.   Knowledge bases in LOOPS are files that are built-up incrementally as a sequence of layers.  Each layer contains updated descriptions of objects.  When a knowledge base is opened, the information in the later layers overrides the information in the earlier layers.  LOOPS makes it possible to select which layers will be used when a knowledge base is opened.  In this example, if the knowledge base is opened and only the first 2 layers are used, then \lisp{}Obj1\rm{} will have an \lisp{}x\rm{} variable with value \lisp{}4\rm{}.  If all three layers were connected, then the value would be \lisp{}8\rm{}.



\parshape 1    0pt  462pt {}


\sl{}Community Knowledge Bases:\rm{}  LOOPS partitions the process of updating a community knowledge base into two steps.  Any user of a community knowledge base can make tentative changes to a community knowledge base in his own (isolated) environment.  These changes can be saved in a layer of his personal knowledge base, and are marked as associated with the community knowledge base.  In a separate step, a data base manager can later copy such layers into a community knowledge base.  This separation of tasks is intended to encourage experimentation with proposed changes.  It separates the responsibility for exploring possibilities from the responsibility of maintaining consistent and standardized knowledge bases for shared use by a community.  The same mechanisms can be used by two individuals using personal knowledge bases to work on the same design.  They can conveniently exchange and compare layers that update portions of a design.        

\sl{}Unique Identifiers:\rm{}  The ability to determine when different layers are referring to the same entity is critical to the ability to share data bases.  To support this feature the LOOPS data base assigns unique identifiers (based on the computer's identification numbers, the date, and an unbounded count) to objects before they are written to a knowledge base.  This facility provides a grounding for more sophisticated notions of equality that might be desired in knowledge representation languages built on LOOPS.	 

\sl{}Environments:\rm{}{\send1{(USINGKBSUB1.IM;4 3340 \count0)}}  A user of LOOPS works in a personalized \sl{}environment\rm{}.  An environment provides a lookup table that associates unique identifiers with objects in the connected knowledge bases.  In an environment, user indicate dominance relationships between selected knowledge bases.  When an object is referenced through its unique identifier, the dominance relationships determine the order in which knowledge bases are examined to resolve the reference.  By making personal knowledge bases dominate over community knowledge bases, a user can override portions of community knowledge bases with his own knowledge bases.  

\sl{}Multiple Alternatives:\rm{}{\send1{(USINGKBSUB1.IM;4 4011 \count0)}}  An important use of environments is for providing speedy access to alternative versions (e.g., multiple alternatives in a design).  A user can have any number of environments available at the same time.  Each environment is fully isolated from the others.  Operations that move information between environments are always done explicitly through knowledge bases.










\vskip10pt

\bf{}\noindent\save0\hbox{9.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Environmental Objects and Boot Layers

\rm{}\penalty 2000
{\send1{(USINGKBSUB1.IM;4 4533 \count0)}}\penalty 2000
\mark{Environmental Objects and Boot Layers}
\penalty 2000
\vskip10pt
\penalty 2000
Knowledge bases, environments, and layers are represented in Loops by special objects called \sl{}environmental objects\rm{}.{\send1{(USINGKBSUB1.IM;4 4685 \count0)}}  All knowledge base and environment operations are performed by sending messages to these objects.  Environmental objects are accessible from any environment in Loops.  

In this section, we will need to distinguish between environmental objects and the things that they represent.  figure X.X summarizes some of the terminology that we will use.




\vskip 10pt
{\send1{(USINGKBSUB1.IM;4 5092 \count0)}}\parshape 1   46pt  416pt {}

\stretchyspaceskip{}\ragged 9999{}

\parshape 0 {}

\vskip 10pt
\hbox{\vbox{

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 89pt{\sl{}Loops Object\rm{}}\cr\noalign{\hskip15pt}
\hbox par 89pt{\sl{}Represents\rm{}}\cr\noalign{\hskip15pt}
\hbox par 208pt{\sl{}Description\rm{}}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 89pt{Layer}\cr\noalign{\hskip15pt}
\hbox par 89pt{file layer}\cr\noalign{\hskip15pt}
\hbox par 208pt{Portion of a file which contains descriptions of objects.}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 89pt{KB}\cr\noalign{\hskip15pt}
\hbox par 89pt{knowledge base}\cr\noalign{\hskip15pt}
\hbox par 208pt{A file and sequence of file layers.  A knowledge is known by the name field of its file name.}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 89pt{KBState}\cr\noalign{\hskip15pt}
\hbox par 89pt{State of a knowledge base}\cr\noalign{\hskip15pt}
\hbox par 208pt{A sequence of file layers.  Used to access a fixed explicit set of file layers (e.g., a version of a knowledge base that is older than the most recent version).}\cr\noalign{\hskip15pt}
}}

\vskip 10pt
\hbox{\hskip 46pt\valign{#\vfill\cr\hbox par 89pt{Environment}\cr\noalign{\hskip15pt}
\hbox par 89pt{environment}\cr\noalign{\hskip15pt}
\hbox par 208pt{An environment associates names and unique identifiers with objects in working memory.}\cr\noalign{\hskip15pt}
}}}}

\ragged 0{}\normalspaceskip{}

\parshape 1   46pt  416pt {}


\parshape 1    0
pt  462pt {}\parshape 1   46pt  416pt {}Figure 12.   Summary of terminology for environmental Loops objects and the entities that they represent.


\parshape 1    0pt  462pt {}


\sl{}Environments:\rm{}{\send1{(USINGKBSUB1.IM;4 5992 \count0)}}  An Environment provides a name space in working memory.  Each Environment associates names and unique identifiers with objects.  In general, Environments are designed to be independent.  For convenience, Environments are usually named.  An Environment is always associated with a particular knowledge base.   The specifications for creating an Environment come from some knowledge base, and changes to the Environment are stored on that knowledge base.


\sl{}Layers:\rm{}{\send1{(USINGKBSUB1.IM;4 6475 \count0)}}  A file layer is a portion of a file which contains descriptions of objects.  An object description consists of a unique identifier and an expression that can be read by Interlisp to create the Loops object.  A different unique identifier is associated with each expression.  In addition, a file layer contains a mapping from names (Interlisp atoms) to unique identifiers.  A file layer is represented in Loops by a Layer object.  A Layer indicates the file on which it is written, the starting address of the file layer, and the name of the knowledge base with which it is conceptually associated.  A Layer also contains various bookkeeping information such as the name of its creator and the date of its creation.


\sl{}KBs and KBStates:\rm{}{\send1{(USINGKBSUB1.IM;4 7227 \count0)}}{\send1{(USINGKBSUB1.IM;4 7243 \count0)}}  A knowledge base is a set of file layers.  Typically, most of the layers of a knowledge base are located on a single file.  A knowledge base is known by its file name.  By convention, such files have the extension {\lquotes}\lisp{}KB\rm{}{\rquotes}.  A KB is a Loops object that represents a knowledge base.  A KB has a name equal to the name field of the file name of the knowledge base that it represents.  For example, the KB with name \lisp{}Test\rm{} would be associated with a version of the file \lisp{}Test.KB\rm{}.

A KBState is a generalization of a KB.  It refers to an explicit set of file layers.  KBs and KBStates indicate their Layers using a list on an instance variable named \lisp{}contents\rm{}.{\send1{(USINGKBSUB1.IM;4 7949 \count0)}}{\send1{(USINGKBSUB1.IM;4 7982 \count0)}}  An element of this list must be either a Layer or a KBState.  When a KBState appears in the list, it is as if the Layers listed in the KBState's contents variable appeared explicitly in the list.  This provides a mechanism for indirect fetching of layers from other knowledge bases.  

To indicate all of the layers of the most recent version of a knowledge base, the contents of the KBState can be the special value {\lquotes}\lisp{}CURRENT\rm{}{\rquotes}.  When such a KBState appears in the list, it is as if the Layers of the most recent version of the knowledge base were inserted in the list.  These Layers are retrieved by retrieving the KB from the referenced knowledge base.


\sl{}Boot Layers:\rm{}{\send1{(USINGKBSUB1.IM;4 8683 \count0)}}  Environmental objects are distinguished from other objects when they are accessed and when they are written out to a knowledge base.  They are accessed differently in that they are kept in a global name table accessible in all environments.  This means that an Environment can be described in terms of the environmental objects before the Environment is made current.  

Environmental objects are also special in that the file layer that describes them is a special file layer at the end of a knowledge base called the boot layer.  In order to access the contents of a knowledge base, it is necessary to read the boot layer first because it contains the environmental objects that describe the knowledge base.  A boot layer for a knowledge base contains a single KB describing itself, a Layer describing each of its file layers, and the KBStates mentioned (directly or indirectly) in the KB.


\sl{}The Global Name Table:\rm{}{\send1{(USINGKBSUB1.IM;4 9631 \count0)}}  Loops keeps environmental objects in a global name table that is accessible from any environment.  This name table also includes the basic classes that are part of the Loops kernel.  If Loops is used without exercising the Environments feature, then all created objects are also placed in the global table.

When another environment is opened, objects not in core are first looked for by UID or name in the open environment.  If no object is found there, then the UID or name is looked up in the Global Environment.  Thus, object descriptions in a new environments override those in Global Envrionment, but old objects which have no counterparts are still available.










\vskip10pt

\bf{}\noindent\save0\hbox{9.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Starting With No Preexisting Knowledge Bases

\rm{}\penalty 2000
{\send1{(USINGKBSUB1.IM;4 10475 \count0)}}\penalty 2000
\mark{Starting With No Preexisting Knowledge Bases}
\penalty 2000
\vskip10pt
\penalty 2000
The knowledge base facility in Loops has been designed to cover a number of situations.  Because of this generality, it is not always easy for a newcomer to discover the simplest way of using the features.  The following sections describe all the features of the Knowledge Base system;  however each feature is introduced within a particular scenario that shows how to do some of the most common operations for which Loops was designed. 

In the first scenario, a user wants to start from scratch using no preexisting knowledge bases.  The results of this Loops session are saved in a personal knowledge base.	  

When a user invokes Loops, the Loops name space will contain some objects from the Loops kernel.  Before creating any new objects, the user should type an expression of the form:



\lisp{}{\nofill{}({\char'137} {\char'44}KB New '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{} \arg{}newVersionFlg\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 11381 \count0)}}

where \arg{}KBName\rm{} is an atom (e.g., use \lisp{}FOO\rm{} to create a knowledge base named \lisp{}FOO.KB\rm{}) and \arg{}environmentName\rm{} will be the name of the Environment.  This will create both a new KB corresponding to the \arg{}KBName\rm{} and a new Environment with the name \arg{}environmentName\rm{}.  

Loops checks that a knowledge base with \arg{}KBName\rm{} does not already exist.  If it does exist and \arg{}newVersionFlg\rm{} is \lisp{}NIL\rm{}, Loops will report an error.  If \arg{}newVersionFlg\rm{} is \lisp{}T\rm{}, then Loops will create a new version of the file.  Because of the way the file system works, the name of a KB must be all in upper case.  If the user attempts to use a \arg{}KBName\rm{} which contains lowercase letters, Loops will correct the name to all upper case and print a warning message.	

Warning:  Objects created before creating and opening an Environment are placed in the global name table.  Hence, any objects so created will be shared by all Environments.  However, Loops will not save such objects in a knowledge base later in the session unless they are explicitly moved to some environment.  Alternatively, such objects can be saved using the Interlisp file package.

The next step is to open the Environment:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Open)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 12675 \count0)}}

This makes the new Environment be the current environment. New objects that are created will be associated with the KB.  

Having created an Environment, the user can then proceed to create whatever new objects he desires in the session.  To dump the current state of the environment and continue afterwards, the user can type:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Cleanup)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 13091 \count0)}}

This does not close any files, and leaves the environment as it was, except that all changed objects have been dumped to the knowledge base, and then marked as unchanged.  \lisp{}Cleanup\rm{} can be done any number of times in a session.  

At the end of a session the user should do a \lisp{}Close\rm{}:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Close)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 13470 \count0)}}


This writes out all of the objects to a file layer, updates the environmental objects accordingly, and writes them out to a boot layer, deletes these objects from memory, and closes all files associated with the environement.  The user can then exit from Interlisp.  After a \lisp{}Close\rm{} is done, the user must go through the following scenario to start up again. 









\vskip10pt

\bf{}\noindent\save0\hbox{9.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Continuing from a Previous Session

\rm{}\penalty 2000
{\send1{(USINGKBSUB1.IM;4 13999 \count0)}}\penalty 2000
\mark{Continuing from a Previous Session}
\penalty 2000
\vskip10pt
\penalty 2000
The case where a user wants to create a new knowledge base is less common than the case where he wants to modify or add objects to a knowledge base that he has previously created.  In this scenario a user wants to resume from where he was at the end of his previous session.	

The first step is to obtain the user's knowledge base, and link it to an environment.  This is done by a message to the class \lisp{}KB\rm{} as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 14517 \count0)}}

This reads the boot layer of the knowledge base named \arg{}KBName\rm{} and creates an Environment named \arg{}environmentName\rm{} that is then connected to the KB.  At this point the user must open the environment to make the contents of the KB available in this environment:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Open)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 14867 \count0)}}

This causes Loops to read in each Layer contained (possibly implicitly) in the contents of the associated KB (named \arg{}KBName\rm{}).  It also makes the new Environment be the current environment.  Having opened an Environment, the user can then proceed to define whatever new objects he desires in the session.  New objects that are created will be associated with the KB.  When he is done, he should type as in the previous scenario:	



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Cleanup)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 15389 \count0)}}

or 



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Close)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 15477 \count0)}}











\vskip10pt

\bf{}\noindent\save0\hbox{9.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Starting from a Community Knowledge Base

\rm{}\penalty 2000
{\send1{(USINGKBSUB1.IM;4 15643 \count0)}}\penalty 2000
\mark{Starting from a Community Knowledge Base}
\penalty 2000
\vskip10pt
\penalty 2000
Users will not usually start from scratch.  Rather, they will often begin by using previously created community knowledge bases.  This scenario starts with obtaining a single community knowledge base.  The user does not own the community knowledge base, so the results of the session will have to be saved in a personal knowledge base.  The personal knowledge base will contain any new objects that created as well as any objects from the community knowledge base that have changed.	

As in the first or second scenario, the first step is to create a personal knowledge base. 



\lisp{}{\nofill{}({\char'137} {\char'44}KB New '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{} \arg{}newVersionFlg\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 16333 \count0)}}

or if the user has a personal knowledge base already, by doing a:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 16492 \count0)}}

This obtains both the KB and an Environment.  The next step is to add the community knowledge base to the KB as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}KBName\lisp{} AddToContents '\arg{}communityKBName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 16718 \count0)}}

where \arg{}communityKBName\rm{} is an atom that is the name of the community knowledge base.  

This step should be repeated for each knowledge base to be added to the KB named \arg{}KBName\rm{}.  The message creates a KBState describing the {\lquotes}current{\rquotes} state of the community knowledge base and adds that KBState to the contents of the KB for the personal knowledge base.  The effect of this action is that Loops will remember to associate the community knowledge base with the user's knowledge base in the future.  (This step need not be repeated in any future session which uses the knowledge base \arg{}KBName\rm{}.)   

At this point, the user can open the Environment as before:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Open)\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 17469 \count0)}}

This causes Loops to read in each Layer contained (possibly implicitly) in the contents of the KB named \arg{}KBName\rm{}.  The \lisp{}Open\rm{} message also makes the Environment named \arg{}environmentName\rm{} be the current environment.  

Since the KB associated with the environment contains a KBState for \arg{}communityKBName\rm{}, those Layers will also be read.  They are found by reading the boot layer of the community knowledge base.  The message \lisp{}AddToContents\rm{} on \arg{}KBName\rm{} will work properly even after the environment is \lisp{}Open\rm{}, in the sense that when it is done on a KB connected to an \lisp{}Open\rm{} environment, it causes all the layers of the newly added KB to be read in.  

All creation and modification operations will take place in this Current Environment.  The user can create new objects and modify objects in the community knowledge base.  When done, the results of the session can be saved using \lisp{}Cleanup\rm{} (or \lisp{}Close\rm{}).  This will cause two file layers to be written out to the personal knowledge base (and none to the community knowledge base).  First a file layer is written out to \arg{}KBName\rm{} for changes made to the community knowledge base (if any).  The Layer for this file layer is marked as associated with the community knowledge base.  Second, a file layer is written out for the other objects that have been created.  The Layer for this is marked as associated with \arg{}KBName\rm{}.  Finally, the environmental objects for the knowledge base are written out to a boot layer.

Before the boot layer is written out, the KB for the personal knowledge base named \arg{}KBName\rm{} is updated to contain the new Layers.  It contains the reference to the community knowledge base that was created by the \lisp{}AddToContents\rm{} message.  This continues to be interpreted as a reference to the most recent version of the community knowledge base named \arg{}communityKBName\rm{}.

If \lisp{}Close\rm{} was used, then the files storing the knowledge bases have been closed and all objects in the environment have been destroyed.  The environment was also made not current.  This clean state is recommended as a place from which the user can then exit from Interlisp.











\vskip10pt

\bf{}\noindent\save0\hbox{9.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Freezing and Thawing References to Knowledge Bases

\rm{}\penalty 2000
{\send1{(USINGKBSUB1.IM;4 19842 \count0)}}\penalty 2000
\mark{Freezing and Thawing References to Knowledge Bases}
\penalty 2000
\vskip10pt
\penalty 2000
In the previous scenarios, the user used the most recent version of the community knowledge base.  Community knowledge bases can be changed over time by their owners (i.e., their human knowledge base managers).  Sometimes a knowledge base manager may update the community knowledge base, but a user may want to continue using a fixed older version.  For example, if the new version of a community knowledge base contains extensive changes, the user may want to finish some project before converting his personal knowledge bases to reflect the changes.  To do this the user must freeze references to the community knowledge base.  Freezing enables a user to continue to access a fixed set of layers even though the community knowledge base may be changed by the knowledge base manager.  In this scenario, the user has a personal knowledge base whose contents include a named community knowledge base.  She anticipates the change to the community knowledge base before it happens and freezes reference to it.  

Later, we will see how a user can return to an earlier version after a change has been made.	

\sl{}Freezing:\rm{}  The first step is to obtain access to the user's personal knowledge base.  As in the previous example, this is done by sending an \lisp{}Old\rm{} message to the class \lisp{}KB\rm{}:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 21229 \count0)}}

This creates an Environment named \arg{}environmentName\rm{} with that KB as its outputKB.  To freeze the reference, the user needs to change the KBState in his personal KB that describes the community knowledge base.  This can be done as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}KBName\lisp{} FreezeKB '\arg{}communityKBName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 21567 \count0)}}

The user can then open his Environment, do his work, and then write updates as before:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Open)
    \sl{}... <make changes to objects> ...\lisp{}
({\char'137} {\char'44}\arg{}environmentName\lisp{} Close)\par}\rm{}




From his point of view, the objects in the community knowledge base will be static even if the knowledge base is changed several times.  After the user ends this session and starts again the next day, his knowledge base will continue to refer to fixed versions of the objects in the community knowledge base, even if new versions are added later.

\sl{}Thawing:\rm{}  Eventually, however, the changes (and improvements) to the community knowledge base may provide a compelling reason for the user to switch to the most recent version.  To do this, he should type the following messages at the beginning of a session:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{})
({\char'137} {\char'44}\arg{}KBName\lisp{} ThawKB '\arg{}communityKBName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB1.IM;4 22529 \count0)}}
{\send1{(USINGKBSUB1.IM;4 22559 \count0)}}

The user can then open his Environment, do his work, and then write updates as before.













\vskip10pt

\bf{}\noindent\save0\hbox{9.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Using Several Knowledge Bases in an Environment

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 126 \count0)}}\penalty 2000
\mark{Using Several Knowledge Bases in an Environment}
\penalty 2000
\vskip10pt
\penalty 2000
The partitioning of knowledge into multiple knowledge bases can be a useful tool for organizing knowledge.  For example, long term storage of different versions of a design can be kept in separate knowledge bases in Loops.  (The different knowledge bases in these cases correspond to different environments.)  It is also convenient to partition knowledge bases to reflect the partitioning of responsibility for setting standards and maintaining consistency.  The previous scenarios have shown the use of separate knowledge bases to keep (tentative, idiosyncratic) personal knowledge separate from (open, standardized) community knowledge.  This scenario shows how a user can access several knowledge bases through a personal knowledge base.	 

The first step is to open the personal knowledge base as follows:




\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}KBName\lisp{} '\arg{}environmentName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 1030 \count0)}}

The next step is to add all of the other knowledge bases that the user wants as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}KBName\lisp{} AddToContents '\arg{}otherKBName\sub{1}\lisp{})
({\char'137} {\char'44}\arg{}KBName\lisp{} AddToContents '\arg{}otherKBName\sub{2}\lisp{})
({\char'137} {\char'44}\arg{}KBName\lisp{} AddToContents '\arg{}otherKBName\sub{3}\lisp{})
...\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 1347 \count0)}}

This can be repeated for each knowledge base to be added.  

Each \lisp{}AddToContents\rm{} message changes the \lisp{}contents\rm{} variable of the knowledge base named \arg{}KBName\rm{} so that it now refers indirectly to the other KBName.  These references are preserved across sessions so that the next time the user opens his knowledge base with an \lisp{}Old\rm{} message, he will not need to repeat the \lisp{}AddToContents\rm{} messages.  These references can be removed as in the previous session.

For most applications, the order in which knowledge bases are added does not matter.  However, if an object reference is ambiguous in the sense that the object is contained in more than one of the knowledge bases, then the last knowledge base added will dominate.  After the knowledge bases have been added, the user can optionally freeze the references to any of them as described earlier.

The next step is to open an environment:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Open)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 2345 \count0)}}

As the user creates new objects in his environment, he could want them to be associated with particular knowledge bases that he is using.  Usually, he will want them associated with his personal knowledge base (named \arg{}KBName\rm{} in the example), and this is the default association.  However, bugs in a community knowledge base will often be found by a user working on an example in a personal knowledge base.  If the user simply changes the buggy objects, they will continue to be associated with the community knowledge base when he saves them at the end of his session.  However, if he creates new objects that he wants associated with the community knowledge base, he can first type:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} AssocKB '\arg{}otherKBName\sub{1}\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 3148 \count0)}}

This message first checks that there is a knowledge base named \arg{}otherKBName\sub{1}\rm{} in the environment.  It does not cause the changes to be written to the other knowledge bases.  Rather, it causes a specially marked layer to be created in the user's personal knowledge base which can be accessed later by the community knowledge base manager.

The user can then create the new objects.  When he is done creating these objects, he can then switch the association back to his personal knowledge base by typing:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} AssocKB '\arg{}KBName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 3764 \count0)}}

As before, the user can type



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Close)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 3877 \count0)}}

when he is done with the session.

Occasionally, a user may accidentally associate some objects with the wrong knowledge base.  See the next section for a way to change the association of an object after it has been created.  

If he later resumes the session, he will have access to all of the knowledge bases that he added.









\vskip10pt

\bf{}\noindent\save0\hbox{9.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Changing the Associations of Objects

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 4373 \count0)}}\penalty 2000
\mark{Changing the Associations of Objects}
\penalty 2000
\vskip10pt
\penalty 2000
The previous scenario depends on anticipating a change in the intended association of an object before creating it.  This approach using an \lisp{}AssocKB\rm{} message works fine if the creation of objects can be conveniently organized into periods such that all of the objects created during a period are associated with the same knowledge base.  In practice, however, a user may forget to send the message or he may later change his mind about the appropriate association for an object.  The message for changing the association of an object is the \lisp{}AssocKB\rm{} message as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}objectName\lisp{} AssocKB '\arg{}newKBName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 5054 \count0)}}









\vskip10pt

\bf{}\noindent\save0\hbox{9.9}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Switching Among Environments

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 5196 \count0)}}\penalty 2000
\mark{Switching Among Environments}
\penalty 2000
\vskip10pt
\penalty 2000
One of the important features of Environments is that they provide a way of having independent versions of designs.  A user can have several open Environments and can switch between them by making one of them the {\lquotes}current{\rquotes} Environment.  In this scenario, we will first consider two ways that a user can create multiple open Environments.  Then we will consider how to switch among them and how to copy objects between them.

\sl{}Case 1.\rm{}  In this case, a user is just starting a session.  He has a personal knowledge base named \lisp{}KBName1\rm{}, and he wants to create two knowledge bases (\lisp{}KBName2\rm{} and \lisp{}KBName3\rm{}) to represent two versions of a design.  To do this, the user can type:



\lisp{}{\nofill{}({\char'137} {\char'44}KB New 'KBName2 '\arg{}environmentName2\lisp{})
                   \sl{}Create 2nd knowledge base and Environment.\lisp{}
({\char'137} {\char'44}KB New 'KBName3 '\arg{}environmentName3\lisp{})
                   \sl{}Create 3rd knowledge base and Environment.\lisp{}
({\char'137} {\char'44}KBName2 AddToContents 'KBName1)
                   \sl{}Add KBName1 to the contents of 2nd KB.\lisp{}
({\char'137} {\char'44}KBName3 AddToContents 'KBName1)
                   \sl{}Add KBName1 to the contents of 3rd KB.\lisp{}
({\char'137} {\char'44}\arg{}environmentName2\lisp{} Open)
                   \sl{}Open the 2nd Environment.\lisp{}
({\char'137} {\char'44}\arg{}environmentName3\lisp{} Open)
                   \sl{}Open the 3rd Environment, leaving it as current.\lisp{}\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 6545 \count0)}}
{\send1{(USINGKBSUB2.IM;5 6582 \count0)}}
{\send1{(USINGKBSUB2.IM;5 6619 \count0)}}



\sl{}Case 2.\rm{}  Alternatively, the user may discover part way through a session that he wants to branch out with another Environment.  In this scenario, the user is working in Environment1 and decides to create a branch point.  Before doing this, the user must first Close that environment:  



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName1\lisp{} Close)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 6997 \count0)}}

The user can then create the Environment2 and Environment3 as in case 1.

\sl{}Switching.\rm{}  In both cases, the last Environment opened will be the default current one.  The user can make any Environment be current by:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName2\lisp{} MakeCurrent)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 7311 \count0)}}

All Loops operations will then happen in this Environment.  To switch to \arg{}environmentName3\rm{} use:	



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName3\lisp{} MakeCurrent)\par}\rm{}



and so on.  To test whether any particular environment, \arg{}testedEnvironment\rm{} is current, one uses:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}testedEnvironment\lisp{} IsCurrent)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 7662 \count0)}}

To switch to the GlobalEnvironment, one sends to the current environments:



\lisp{}{\nofill{}({\char'137} CurrentEnvironment MakeNotCurrent)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 7835 \count0)}}

The Lisp global variable \lisp{}CurrentEnvironment\rm{}{\send1{(USINGKBSUB2.IM;5 7916 \count0)}} is bound to the environment which is current.

When done, the updates should be written out for all of the open Environments.  This can be done by sending \lisp{}Cleanup\rm{} or \lisp{}Close\rm{} messages to each of the environment, or can be done by sending the corresponding message to the class Environment which will send the message on to each open environment (kept on a list in the Lisp global variable \lisp{}openEnvironments\rm{}):{\send1{(USINGKBSUB2.IM;5 8369 \count0)}}



\lisp{}{\nofill{}({\char'137} {\char'44}Environment Cleanup)
({\char'137} {\char'44}Environment Close)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 8473 \count0)}}
{\send1{(USINGKBSUB2.IM;5 8515 \count0)}}


\sl{}Copying Objects between Environments.\rm{}  While a user is switching between environments, he may make discover an error in some information that is global to both environments.  In this scenario, the user discovers an error in some objects from a community knowledge base while he is working in Environment2. He corrects the objects in Environment2, and wants to copy those corrections into Environment3.  He does this using the \lisp{}CopyObjects\rm{} message as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}toEnvironment\lisp{} CopyObjects \arg{}objectsList\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 9098 \count0)}}

where \arg{}toEnvironment\rm{} is the name of the environment that the objects are copied to, and \arg{}objectsList\rm{} is a list of objects to be copied.  

This message causes the objects to be copied.  If the objects already exist in the \arg{}toEnvironment\rm{}, then the copies overwrite the previous objects.  

In our scenario, the user would perform the following steps:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName2\lisp{} MakeCurrent)
                   \sl{}Make Environment2 current.\lisp{}
...
                   \sl{}Collect the objects.\lisp{}
(SETQ objectsList ...)
                   \sl{}Make a list of the collected objects.\lisp{}
({\char'137} {\char'44}\arg{}environmentName3\lisp{} CopyObjects objectList)
                   \sl{}Copy the objects to Environment3.\lisp{}\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 9854 \count0)}}
{\send1{(USINGKBSUB2.IM;5 9898 \count0)}}










\vskip10pt

\bf{}\noindent\save0\hbox{9.10}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Saving Parts of a Session

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 10027 \count0)}}\penalty 2000
\mark{Saving Parts of a Session}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}Saving part of a session.\rm{}  To selectively update the knowledge base with some of the changes that he made in a session, a user can send a \lisp{}Cleanup\rm{} message to his Environment with KBs specified.  For example, to save the updates associated only with the knowledge bases named \lisp{}KBName1\rm{} and \lisp{}KBName2\rm{}, he can send the message:	



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Cleanup '(KBName1 KBName2))\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 10482 \count0)}}

This message writes out file layers to the user's personal knowledge base containing the objects that from the current Environment that are associated with the knowledge base \lisp{}KBName1\rm{} and \lisp{}KBName2\rm{}.  The user has omitted the names of associated knowledge bases for which he wants to discard the changes.  This message completes by writing out the boot layer.

The \lisp{}Cleanup\rm{} message without KB's specified writes a layer for every associated knowledge base that has been changed, followed by a \lisp{}WriteBoot\rm{}.  If the user does a \lisp{}({\char'137} {\char'44}\arg{}envName\lisp{} Cleanup T)\rm{}, then all the changes will be written out in a single layer associated with the connected knowledge base.	   

\sl{}Cancelling an entire session.\rm{}  The previous scenarios assumed that a user wanted to save the changes that he makes in a session.  Sometimes, however, a user may prefer to discard the changes that he has made in a session.  He can do this and return the environment to an unopened state by typing:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Cancel)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 11564 \count0)}}

Cancelling this session will not go back past the last time the user did a \lisp{}Cleanup\rm{}.  \lisp{}Cancel\rm{} backs up changes made since that time and then does what a \lisp{}Close\rm{} would do, destroying objects in the environment, and closing files.









\vskip10pt

\bf{}\noindent\save0\hbox{9.11}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Copying Layers from one Knowledge Base to Another

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 11984 \count0)}}\penalty 2000
\mark{Copying Layers from one Knowledge Base to Another}
\penalty 2000
\vskip10pt
\penalty 2000
The ability to describe layers using a KBState makes it possible for one knowledge base to indirectly access the file layers of another one.  This mechanism works fine when it is used to extend a personal knowledge base to include a community knowledge base.  It enables several users to read a community knowledge base at the same time and to write their updates to their personal knowledge bases.  However, the indirection mechanism breaks down if some users want to read a knowledge base while another user is writing to it.  For example, such a conflict could arise if a community knowledge base used the indirection mechanism to access a file layer in some personal knowledge base.  Whenever the owner of the personal knowledge base was updating it, users of the community knowledge base would be blocked by the file system.  To avoid such situations, it is necessary to create community knowledge bases that physically contain all of the file layers that they reference.	

In this scenario, the user is just starting a session and no knowledge bases have been opened.  The user wants to copy information from a knowledge base named \arg{}fromKBName\rm{} to a knowledge base named \arg{}toKBName\rm{}.  The first step is to read the boot layers of the two knowledge bases. 



\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}fromKBName\lisp{})
({\char'137} {\char'44}KB Old '\arg{}toKBName\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 13356 \count0)}}

In this scenario, one need not, and in fact should not, have an envrionment open or either of the two KBs connected to an environment.  All the work will go on in the Global Environemnt.

The second step is to create a description of the layers to be moved.  This description can be either a Layer or a KBState.  One way to create this description is to use any of the object editors available in Loops.  Another way is to send a \lisp{}DescribeLayers\rm{} message as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}fromKBName\lisp{} DescribeLayers \arg{}DateOrDays\lisp{} \arg{}associatedKB\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 13957 \count0)}}


\arg{}DateOrDays\rm{} can be an Interlisp Date or an integer number of days.  If it is a date, then only those Layers created on or after the given date will be described.  If it is an integer, then only Layers created within that many days will be described.  If it is \lisp{}NIL\rm{}, then no date filter will be applied.   

\arg{}associatedKB\rm{} is the name of the knowledge base with which the Layers are associated.  (If \lisp{}NIL\rm{}, then the layers associated with any knowledge base will be described.)

For example:



\lisp{}{\nofill{}(SETQ layerDescription
          ({\char'137} {\char'44}\arg{}fromKBName\lisp{} DescribeLayers 14 '\arg{}toKBName\lisp{}))\par}\rm{}



returns a KBState describing the Layers created in the last fourteen days in the knowledge base named \arg{}fromKBName\rm{} that are associated with the knowledge base named \arg{}toKBName\rm{}.   

Given such a description, the layers can be copied by typing:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}toKBName\lisp{} CopyFileLayers layerDescription)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 14926 \count0)}}









\vskip10pt

\bf{}\noindent\save0\hbox{9.12}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Summarizing and Combining Knowledge Bases

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 15107 \count0)}}\penalty 2000
\mark{Summarizing and Combining Knowledge Bases}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}Summarizing a Knowledge Base.\rm{}  As knowledge bases evolve over time, the number of layers and amount of overridden information can consume a large fraction of the file space.  Economy-minded knowledge base managers may want to create {\lquotes}compressed{\rquotes} versions of knowledge bases that have all of the information contained in just one layer.  In this scenario, the user starts a session by typing:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Summarize \arg{}fromKBName\lisp{} \arg{}toKBName\lisp{} \arg{}assocKBNames\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 15624 \count0)}}

where \arg{}fromKBName\rm{} is the knowledge base to be summarized; \arg{}toKBName\rm{} is the knowledge base to be created.  It must be a different name than \arg{}fromKBName\rm{}; \arg{}assocKBNames\rm{} must be a list of KBNames or \lisp{}NIL\rm{}.  If  it is list, then all, and only those objects with associated KB's on the list will be dumped to the file.  One must include \arg{}fromKBName\rm{} on \arg{}assocKBNames\rm{} if changes and objects associated with it are to be dumped to the file.  If \arg{}assocKBNames\rm{} = \lisp{}NIL\rm{}, all objects on the file will be dumped on a single layer if \arg{}toKBName\rm{}.

This message causes Loops to read the boot layer of the old knowledge base (\arg{}fromKBName\rm{}), create a new knowledge base (\arg{}toKBName\rm{}), create an Environment associated with the new knowledge base, read in all of the objects in \arg{}fromKBName\rm{}, write them out to a single layer, and then write a boot layer for the new knowledge base.

\sl{}Combining Knowledge Bases.\rm{}  The \lisp{}Summarize\rm{} message can also be used to combine several existing knowledge bases into a single new knowledge base.  In this case, the message is as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Summarize \arg{}fromKBNames\lisp{} \arg{}toKBName\lisp{} \arg{}assocKBNames\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 16875 \count0)}}

where \arg{}fromKBNames\rm{} is a list of the names of the knowledge bases to be summarized; \arg{}toKBName\rm{} is the name of the new knowledge base to be created; \arg{}assocKBNames\rm{} is as described above.

This message causes Loops to read the boot layers of the old knowledge bases, creates a new knowledge base (\arg{}toKBName\rm{}), creates an Environment associated with the new knowledge base, reads in all of the objects, writes them out to a single layer, and then writes a boot layer for the new knowledge base.

The user can create a new knowledge base which contains all of the objects in any open environment.  This may include objects from any number of KB's.



\lisp{}{\nofill{}({\char'137} \arg{}environment\lisp{} DumpToKB \arg{}toKBName\lisp{} \arg{}assocKBNames\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 17654 \count0)}}

will create a new KB named \arg{}toKBName\rm{}, and dump from the environment all objects with associated KB on the list \arg{}assocKBNames\rm{} onto \arg{}toKBName\rm{} (or all objects if \arg{}assocKBNames\rm{} = \lisp{}NIL\rm{}).     









\vskip10pt

\bf{}\noindent\save0\hbox{9.13}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Subdividing a Knowledge Base

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 18015 \count0)}}\penalty 2000
\mark{Subdividing a Knowledge Base}
\penalty 2000
\vskip10pt
\penalty 2000
Sometimes a user may want to subdivide a knowledge base so that a subset of the objects are moved away to create a new knowledge base.  In our scenario, the user wants to move the objects from a knowledge base in \arg{}fromEnvironmentName\rm{} to a knowledge base (\arg{}toKBName\rm{}) included in \arg{}toEnvironmentName\rm{}.  In the first step of this scenario the user uses the \lisp{}MapObjectNames\rm{} message:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} MapObjectNames (FUNCTION \arg{}UserFn\lisp{}) \arg{}AssocKBs\lisp{} \arg{}NoUIDs\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 18568 \count0)}}

where

\arg{}UserFn\rm{} is a function that will be applied to every object name.  If \lisp{}NIL\rm{}, then a list of object names and UIDs in environment is returned as the value of the message. If it is the atom \lisp{}T\rm{}, then only names which are not UIDs will be returned. 

\arg{}AssocKBs\rm{} is an optional argument.  If an atom, it is interpreted as the name of the associated knowledge base for the objects.  If a list, will be interpreted as a list of associated knowledge bases for the object.  If \lisp{}NIL\rm{}, only objects associated with the current AssocKB of the Environment will be used.

If \arg{}NoUIDs\rm{} is \lisp{}T\rm{}, then \arg{}UserFn\rm{} will only be applied to real names, and not UIDs.

In our scenario, we will assume that \lisp{}MyFn\rm{} will create a list of the objects (\lisp{}objectList\rm{}) that the user wants to move.  The user switches to the source environment, finds the objects and moves them:	



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}fromEnvironmentName\lisp{} MakeCurrent)
                   \sl{}Switch to fromEnvrionment.\lisp{}
({\char'137} {\char'44}\arg{}fromEnvironmentName\lisp{} MapObjectNames (FUNCTION MyFn))
                   \sl{}Make list of objects.\lisp{}\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 19727 \count0)}}
{\send1{(USINGKBSUB2.IM;5 19774 \count0)}}

The next step is to move the objects as follows:



\lisp{}{\nofill{}(SETQ newObjectList
     ({\char'137} {\char'44}\arg{}toEnvironmentName\lisp{} MoveObjects objectList)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 19943 \count0)}}

This causes the objects to be copied to toEnvironment and deleted from fromEnvironment (or whatever Environment they came from).  The objects will continue to be associated with whatever AssocKB they were before.  In this scenario, however, the user wishes them be associated with the knowledge base named toKBName.	



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}fromEnvironmentName\lisp{} MakeCurrent)
(for object in newObjectList do ({\char'137} object AssocKB 'toKBName)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 20421 \count0)}}
{\send1{(USINGKBSUB2.IM;5 20461 \count0)}}

The final step is to write out the changes:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}environmentName\lisp{} Cleanup)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 20593 \count0)}}









\vskip10pt

\bf{}\noindent\save0\hbox{9.14}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Going Back to a Previous Boot Layer of a Knowledge Base

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 20781 \count0)}}\penalty 2000
\mark{Going Back to a Previous Boot Layer of a Knowledge Base}
\penalty 2000
\vskip10pt
\penalty 2000
Since knowledge bases are represented as objects, it is possible to reconfigure their contents using the standard object access functions.  However if a Layer has been deleted from the contents of a KB, that layer is no longer written out to the boot layer.  This can make it difficult to get back to versions modified in this way.  The following message makes it possible restore such knowledge bases by reading in old boot layers: 



\lisp{}{\nofill{}({\char'137} {\char'44}KB ReadOldBootLayer '\arg{}KBName\lisp{} \arg{}numberBack\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 21328 \count0)}}

The value returned is a KB which has the name KBName, and the state corresponding to the boot layer specified.  To preserve a KBState which has these contents, the user can then use:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}KBName\lisp{} Copy)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 21575 \count0)}}










\vskip10pt

\bf{}\noindent\save0\hbox{9.15}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Affecting what is Saved

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 21727 \count0)}}\penalty 2000
\mark{Affecting what is Saved}
\penalty 2000
\vskip10pt
\penalty 2000
The user may not wish an object, or some part of an object saved on a knowledge base.  In this section, we describe a number of ways of stopping information from being written on the knowledge base, with appropriate caveats for the use of these features.





\vskip10pt

\bf{}\noindent\save0\hbox{9.15.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Temporary Objects

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 22051 \count0)}}\penalty 2000
\mark{Temporary Objects}
\penalty 2000
\vskip10pt
\penalty 2000
If the user is creating lots of objects for temporary use (as intermediate products of a computation) then none of those objects are useful after the computation is done.  To create such objects, the user should use:



\lisp{}{\nofill{}({\char'137} \arg{}class\lisp{} NewTemp)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 22331 \count0)}}

to create them instead of the usual \lisp{}({\char'137} \arg{}class\lisp{} New)\rm{} message.  Objects created in this way will not be given a UID, and will be not be accessible by mapping through the environment.  If by some chance they are referenced from some object that is being dumped to the data base, they will then be converted into permanent objects, and dumped to that same KB.









\vskip10pt

\bf{}\noindent\save0\hbox{9.15.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Not Saving some IV values

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 22816 \count0)}}\penalty 2000
\mark{Not Saving some IV values}
\penalty 2000
\vskip10pt
\penalty 2000
For some instances, it is useful to store in an instance variable a Lisp dataytpe (e.g. a pointer to a window, or hash array).  However, most Lisp datatypes are not stored appropriately on a KB.  In general, when read back in from a KB, what was formerly an instance of a datatype looks like an atom with a funny printname.  The solution we have adopted is to allow the user to specify IV values or properties which should not be dumped to a knowledge base.  When read back in, the IV value or property will inherit the default value from the class which can be an active value to recreate the desired Lisp object.

For example, the class \lisp{}{\char'44}Environment\rm{} uses a hash table as the value of its IV nameTable.  The following fragment of the definition of Environment shows how saving the value of \lisp{}nameTable\rm{} is suppressed and how an active value is used to recreate it.



\lisp{}{\nofill{}[DEFCLASS Environment ...
      (InstanceVariables ...
         (nameTable {\char'43}(NIL NewNameTable) DontSave Any)
	...]\par}\rm{}



Any instance of environment will have \lisp{}nameTable\rm{} filled in by \lisp{}NewNameTable\rm{} the first time it is accessed.  \lisp{}NewNameTable\rm{} is a specialized version of \lisp{}FirstFetch\rm{} which makes the local value be a hashArray. The property \lisp{}DontSave\rm{} with value \lisp{}Any\rm{} (which is inherited in every instance) specifies that nothing about the IV \lisp{}nameTable\rm{} should be saved on a KB.  For finer control, the property \lisp{}DontSave\rm{} could have been given a value which is a list of property names whose values should not be saved on the KB.  If the atom \lisp{}Value\rm{} is included in the list, then the value of the IV itself will not be saved.  The value \lisp{}Any\rm{} for \lisp{}DontSave\rm{} is interpreted as meaning no porperty or value should be saved. 









\vskip10pt

\bf{}\noindent\save0\hbox{9.15.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Ignoring changes on an IV

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 24711 \count0)}}\penalty 2000
\mark{Ignoring changes on an IV}
\penalty 2000
\vskip10pt
\penalty 2000
Whenever an object is modified during the course of a session, it is marked as changed so that a new version of the object will be written out on the KB.  Suppose the user may be using an IV globally known object as a place to cache some information.  In this case the user does not need or even want the known object to be marked as changed if the only change made was to store the cached information.  To allow this, the special active value function \lisp{}StoreUnmarked\rm{} is provided which does not mark the object as changed when it updates its localState.  For example, if \lisp{}{\char'44}WorldView\rm{} had an instance variable \lisp{}lastSelected\rm{} which was updated each time a selection was made, then if \lisp{}{\char'44}WorldView\rm{} looked like:



\lisp{}{\nofill{}[DEFINST WorldView ...
   (lastSelected {\char'43}(obj1 NIL StoreUnmarked) ...]\par}\rm{}



changes to \lisp{}lastSelected\rm{} would be ignored by the KB system.  It is often useful to combine this feature with \lisp{}DontSave\rm{} described earlier so that when the object is dumped to a KB (because of some other change) the value in this IV is not saved.  Then the \lisp{}activeValue\rm{} can be inherited directly from the default value in the class.  Using \lisp{}DontSave\rm{} by itself is not sufficient to ensure that the object will not be dumped if a value is changed in the not to be saved IV.  









\vskip10pt

\bf{}\noindent\save0\hbox{9.15.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Getting rid of objects explicitly

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 26160 \count0)}}\penalty 2000
\mark{Getting rid of objects explicitly}
\penalty 2000
\vskip10pt
\penalty 2000
During the course of a session users may create a number of objects they discover before the end of the session are not needed.  They may also decide that some old objects are no longer needed.  By using:



\lisp{}{\nofill{}({\char'137} \arg{}obj\lisp{} Destroy)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 26426 \count0)}}

for each such object, the user will cause any new objects to be forgotten (not written to the KB) and the incore space reclaimed.  For objects which were in the KB previously, there will be stored an indication that this object has been deleted, so that later reading of this KB will not contain the object.













\vskip10pt

\bf{}\noindent\save0\hbox{9.16}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Examining Environmental Objects

\rm{}\penalty 2000
{\send1{(USINGKBSUB2.IM;5 26919 \count0)}}\penalty 2000
\mark{Examining Environmental Objects}
\penalty 2000
\vskip10pt
\penalty 2000
Sending the message \lisp{}MapObjectNames\rm{} to an open environment allows one access to the names and UIDs of objects in that environment.  From the names and UIDs one can then access the objects themselves using \lisp{}GetObjectRec\rm{}.  One can determine the names and UIDs of objects in a Layer by sending that layer the message \lisp{}MapObjectNames\rm{}.  The form is:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}Layer1\lisp{} MapObjectNames \arg{}mapFn\lisp{} \arg{}noUIDs\lisp{})\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 27394 \count0)}}

which applies \arg{}mapFn\rm{} to each name (and to each UID unless \arg{}noUIDs\rm{}=\lisp{}T\rm{}).  If \arg{}mapFn\rm{}=\lisp{}NIL\rm{} then this simply returns a list of the names (and UIDs).  However, unless the layer has been read in to an environment, one cannot get the object associated with that name (UID) on that layer.

\sl{}PrettyPrinting a KB:\rm{}  A special pretty printing function is available for KB's, KBStates, and Layers which tell about its history and contents.  If one does:



\lisp{}{\nofill{}({\char'137} {\char'44}KB Old '\arg{}KBName\lisp{})\par}\rm{}



without necessarily opening an environment, then one can send:



\lisp{}{\nofill{}({\char'137} {\char'44}\arg{}KBName\lisp{} PP)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 28022 \count0)}}

to see what is in the KB and its containing layers.

\sl{}ChangedKBs:\rm{}  In a particular environment, one can change objects which originate on any number of community and personal knowledge bases.  To find out the names of any KBs that have modified entities associated with them, one send to that environment, say \lisp{}E1\rm{}:



\lisp{}{\nofill{}({\char'137} {\char'44}E1 ChangedKBs)\par}\rm{}


{\send1{(USINGKBSUB2.IM;5 28422 \count0)}}

It is this list which is used by \lisp{}Cleanup\rm{} to determine the set of layers that will be dumped at cleanup time.












\vskip10pt

\bf{}\noindent\save0\hbox{9.17}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class KBState

\rm{}\penalty 2000
{\send1{(KBGUTS.IM;3 66 \count0)}}\penalty 2000
\mark{The Class KBState}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip 10pt
{\send1{(KBGUTS.IM;3 110 \count0)}}\formatdef{462pt}{\lisp{}KBState\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 


\parshape 1    0pt  462pt {}

IVs:



\vskip 10pt
{\send1{(KBGUTS.IM;3 165 \count0)}}\formatdef{462pt}{\lisp{}name\rm{}}{IV of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Name of file associated with this KBState.  \lisp{}NIL\rm{} as value here overrides active value in named object.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 329 \count0)}}\formatdef{462pt}{\lisp{}contents\rm{}}{IV of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Either \lisp{}CURRENT\rm{}, meaning the current state of the KB with name or a list of layers and KBStates specifying layerset)


\parshape 1    0pt  462pt {}


Methods:




\vskip 10pt
{\send1{(KBGUTS.IM;3 599 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} AddEntities \arg{}entityList\lisp{})\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Add all items on \lisp{}contents\rm{} and \arg{}self\rm{} to \arg{}entityList\rm{}. Called by functions which write out the boot layer to make sure that all layers are added to the list of items to be dumped.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 934 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} AddToContents \arg{}newAddition\lisp{})\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Adds a new item to \lisp{}contents\rm{} of KB.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 1101 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Connect \arg{}nameTable\lisp{})\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Read in object file indices from all, possibly implicit, layers in order. These are being opened for input only.


\parshape 1    0
pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 1323 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} CurrentState)\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Create a KB state which reflects the current state of this KB.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 1549 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} DescribeLayers \arg{}dateOrDays\lisp{} \arg{}assocKB\lisp{})\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Return a KBState whose contents are just those layers which occur after \arg{}dateOrDays\rm{} and have KB \arg{}assocKB\rm{}, or \lisp{}NIL\rm{} if none.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 1807 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Files \arg{}fileList\lisp{})\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}fileList\rm{} is a \lisp{}TCONC\rm{} list of files already found.  Add any new ones found.  Very similar in structure to \lisp{}KBState.Connect\rm{}.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 2039 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} MyKB)\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Return the KB object corresponding to this KBState.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 2192 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ReadBoot)\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Read the boot file for this KB.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 2345 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} SetContents \arg{}lst\lisp{})\rm{}}{Method of KBState}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Make KB have new contents.  Check types of elements.


\parshape 1    0pt  462pt {}












\vskip10pt

\bf{}\noindent\save0\hbox{9.18}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class KB

\rm{}\penalty 2000
{\send1{(KBGUTS.IM;3 2495 \count0)}}\penalty 2000
\mark{The Class KB}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip 10pt
{\send1{(KBGUTS.IM;3 2533 \count0)}}\formatdef{462pt}{\lisp{}KB\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0
pt  462pt {}

IVs:




\vskip 10pt
{\send1{(KBGUTS.IM;3 2593 \count0)}}\formatdef{462pt}{\lisp{}connectedEnvs\rm{}}{IV of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent List of Envs which have read in contents of this KB.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 2695 \count0)}}\formatdef{462pt}{\lisp{}contents\rm{}}{IV of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent KBs start out with an empty list of contents.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 2795 \count0)}}\formatdef{462pt}{\lisp{}currentWriter\rm{}}{IV of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Environment which is currently writing on this KB.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 2895 \count0)}}\formatdef{462pt}{\lisp{}fileName\rm{}}{IV of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Full name of file where this KB is stored.  Computed the first time it is needed.  Never stored.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 3039 \count0)}}\formatdef{462pt}{\lisp{}owners\rm{}}{IV of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent List of owners of this KB.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KBGUTS.IM;3 3113 \count0)}}\formatdef{462pt}{\lisp{}status\rm{}}{IV of KB}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent One of \lisp{}Disconnected\rm{}, \lisp{}Connected\rm{}, or \lisp{}BootNeeded\rm{}.


\parshape 1    0pt  462pt {}



Methods:




\vskip 10pt
{\send1{(KBGUTS.IM;3 3330 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} AddToContents \arg{}newAddition\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Adds a new item to contents of KB.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 3504 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ConnectForOutput \arg{}nameTable\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Read in object file indices from all, possibly implicit, layers in order.  This is being opened for output.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 3737 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} CopyFileLayer \arg{}layer\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Copies the FileLayer referred to by \arg{}layer\rm{} onto \arg{}self\rm{}, and adds a new Layer describing copied fileLayer onto contents of \arg{}self\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 4029 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} CopyFileLayers \arg{}layerDescription\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Copy all the layers in \arg{}layerDescription\rm{} which should be a KBState into \arg{}self\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 4219 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Disconnect)\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Disconnect this KB and close its file if open.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 4379 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} FreezeKB \arg{}name\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Find a KBState with \lisp{}{\char'45}{\char'100}name\rm{}=\arg{}name\rm{} and \lisp{}contents\rm{}=\lisp{}CURRENT\rm{}.  Replace it by a new KBState with \lisp{}contents\rm{} = currentState of myKB.  Return new KBState or \lisp{}NIL\rm{} if failure.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 4703 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} PrintContents \arg{}file\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Fn to Print out a formatted description of the contents of a knowledge base.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 4897 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} SetContents \arg{}lst\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Make KB have new contents.  Check types of elements.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 5059 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ThawKB \arg{}name\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Find a KBState with \lisp{}(GetValue \arg{}self\lisp{} (QUOTE name))\rm{}=\arg{}name\rm{} and \lisp{}contents\rm{} not equal \lisp{}CURRENT\rm{}.  Replace it by a new KBState with \lisp{}contents\rm{} = \lisp{}CURRENT\rm{}.  Return new KBState or \lisp{}NIL\rm{} if failure.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 5391 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} WriteBoot)\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Write out boot file containing KB and all layers and KBStates it contains implicitly or explicitly.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 5704 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} WriteEntityFile \arg{}changedEntities\lisp{} \arg{}namedEntities\lisp{} \arg{}assockbName\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Writes the entities (objects) out to a layer in a given kb.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 5919 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} WriteFileLayer \arg{}kbName\lisp{} \arg{}nameTable\lisp{})\rm{}}{Method of KB}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Writes the facts on the file, appending to file.  Format of layer is: - indexFilePosition (up to 7 characters) - entityCount (up to 7 characters) - nameCount (up to 7 characters) - entity records - indexRecords (UID followed by file position,) - nameRecords (name followed by UID) - initialFilePosition.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{9.19}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class Environment

\rm{}\penalty 2000
{\send1{(KBGUTS.IM;3 6331 \count0)}}\penalty 2000
\mark{The Class Environment}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip 10pt
{\send1{(KBGUTS.IM;3 6379 \count0)}}\formatdef{462pt}{\lisp{}Environment\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}



IVs:



\vskip 10pt
{\send1{(KBGUTS.IM;3 6442 \count0)}}\formatdef{462pt}{\lisp{}status\rm{}}{IV of Environment}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent One of \lisp{}NotOpen\rm{} or \lisp{}Open\rm{}.  \lisp{}Open\rm{} when indexes of KBs have been read in, \lisp{}NotOpen\rm{} after \lisp{}ClearObjectMemory\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 6639 \count0)}}\formatdef{462pt}{\lisp{}nameTable\rm{}}{IV of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent nameTable for looking up UIDs and names.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 6739 \count0)}}\formatdef{462pt}{\lisp{}outputKB\rm{}}{IV of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent KB to which changes will be filed, and which specifies contents.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 6862 \count0)}}\formatdef{462pt}{\lisp{}assocKB\rm{}}{IV of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Name of the KB associated with new objects created.



\parshape 1    0pt  462pt {}


Methods:




\vskip 10pt
{\send1{(KBGUTS.IM;3 7043 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} AssocKB \arg{}akb\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Make \arg{}akb\rm{} be the assocKB of this KB.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 7187 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Cancel)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Erase an environment without cleaning up so that environment is empty, as if it were not open, but it is still connected to the same KB.  Make it not current.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 7456 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ChangedKBs)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Finds the names of all KBs that have any modified entities associated with them.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 7699 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Cleanup \arg{}KBNames\lisp{} \arg{}noBootLayerFlg\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Write FileLayers for KBs named in \arg{}KBNames\rm{}.  If \arg{}KBNames\rm{}=\lisp{}NIL\rm{} then write a layer for each changed KB.  If \arg{}KBNames\rm{}=\lisp{}T\rm{} then write one layer for all changes.  If \arg{}KBNames\rm{} is a single atom, then the update is written for that single assocKB.  Finish by writing new boot layer for outputKB unless \arg{}noBootLayerFlg\rm{} is \lisp{}T\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 8182 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ClearObjectMemory)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Write out boot layer if needed and clear nameTable.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 8358 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Close \arg{}assocKBs\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Cleanup an environment so that all files are closed, and environment is empty, as if it were just created.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 8593 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ConnectOutput \arg{}KB\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Make \arg{}KB\rm{} be the file onto which changes in this Environment will be written.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 8809 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} CopyObjects \arg{}objList\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Copies objects on \arg{}objList\rm{} using the object structure of the object in Environment \arg{}self\rm{} with same UID, if found.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 9091 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} DumpToKB \arg{}kbName\lisp{} \arg{}assocKBNames\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent ???

\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 9216 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Files \arg{}fileLst\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Get a list of all files associated with this environment.  Argument to \lisp{}KBState.Files\rm{} is a \lisp{}TCONC\rm{} list.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 9438 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} IsCurrent)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Test if current.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 9567 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} MakeCurrent)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Set values of \lisp{}CurrentNameTable\rm{} and \lisp{}CurrentEnvironment\rm{} from \arg{}self\rm{} and make \lisp{}DefaultKBName\rm{} be my assocKB.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 9853 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} MakeNotCurrent \arg{}bitchIfNotCurrent\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Makes no Environment Current if this is current, elses causes Error if not Current and \arg{}bitchIfNotCurrent\rm{}=\lisp{}T\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 10154 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} MapObjectNames \arg{}mapFn\lisp{} \arg{}assocKBs\lisp{} \arg{}noUIDs\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}APPLY\rm{} \arg{}mapFn\rm{} to the name of each object stored in the environment.  If \arg{}assocKBs\rm{} given, select only those which are in the list.  If \arg{}noUIDs\rm{}=\lisp{}T\rm{} then apply only to names which are not UIDs.  If \arg{}mapFn\rm{}=\lisp{}NIL\rm{} then just list all names and UIDs; if \arg{}mapFn\rm{}=\lisp{}T\rm{} then just the names.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 10624 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} MarkDeleted \arg{}objToBeDeleted\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Mark object as deleted in KB when new layer is written out.  Done by smashing localRecord field of entity, but NOT storedIn field.  See \lisp{}SelectChangedEntity\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 10886 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Open)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Read in the index of all the layers referred to by contents of outputKB.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 11067 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} WriteBoot)\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Make outputKB write it's boot file.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 11235 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} WriteUpdate \arg{}kbName\lisp{})\rm{}}{Method of Environment}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Write layer for \arg{}kbName\rm{}, or all changes if \arg{}kbName\rm{}=\lisp{}T\rm{}.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{9.20}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class Layer

\rm{}\penalty 2000
{\send1{(KBGUTS.IM;3 11411 \count0)}}\penalty 2000
\mark{The Class Layer}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip 10pt
{\send1{(KBGUTS.IM;3 11452 \count0)}}\formatdef{462pt}{\lisp{}Layer\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0
pt  462pt {}

IVs:



\vskip 10pt
{\send1{(KBGUTS.IM;3 11505 \count0)}}\formatdef{462pt}{\lisp{}file\rm{}}{IV of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Name of the file where FileLayer is found.  Compute it on firstFetch from the kbName by searching directory path.  Don't save full name on file.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 11701 \count0)}}\formatdef{462pt}{\lisp{}kbName\rm{}}{IV of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Name of kb where this layer was stored e.g. BRIDGE.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 11806 \count0)}}\formatdef{462pt}{\lisp{}position\rm{}}{IV of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Index on file where FileLayer is found.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 11898 \count0)}}\formatdef{462pt}{\lisp{}assocKB\rm{}}{IV of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Name of KB with which this Layer is associated conceptually.


\parshape 1    0pt  462pt {}


Methods:




\vskip 10pt
{\send1{(KBGUTS.IM;3 12104 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} AddEntities \arg{}entityList\lisp{})\rm{}}{Method of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Add \arg{}self\rm{} to entity list for dumping on boot layer.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 12285 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Connect \arg{}nameTable\lisp{})\rm{}}{Method of Layer}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Open layer file and read in index.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 12436 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Files \arg{}fileLst\lisp{})\rm{}}{Method of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Add my file to list if it is not already there.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 12634 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} MapObjectNames \arg{}mapFn\lisp{} \arg{}noUIDs\lisp{})\rm{}}{Method of Layer}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Apply \arg{}mapFn\rm{} to objectnames in layer, or make a list of them if \arg{}mapFn\rm{}=\lisp{}NIL\rm{}.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{9.21}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class KBMeta

\rm{}\penalty 2000
{\send1{(KBGUTS.IM;3 12828 \count0)}}\penalty 2000
\mark{The Class KBMeta}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip 10pt
{\send1{(KBGUTS.IM;3 12870 \count0)}}\formatdef{462pt}{\lisp{}KBMeta\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 


\parshape 1    0pt  462pt {}

Methods:



\vskip 10pt
{\send1{(KBGUTS.IM;3 13045 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} New \arg{}kbName\lisp{} \arg{}envName\lisp{} \arg{}newVersionFlg\lisp{})\rm{}}{Method of KBMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Create a new KnowledgeBase file, and an environment if \arg{}kbName\rm{} is given, and make environment current.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 13286 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Old \arg{}kbName\lisp{} \arg{}envName\lisp{})\rm{}}{Method of KBMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Get KB for this kbName.  (Causes boot layer to be read unless KB is already in the global table.)  If \arg{}envName\rm{} is given, creates an Environment of that name and connects the environment to the KB.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 13589 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ReadBoot)\rm{}}{Method of KBMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Read in index of existing KB given kbName.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 13791 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} ReadOldBootLayer \arg{}kbName\lisp{} \arg{}numBack\lisp{})\rm{}}{Method of KBMeta}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Read in index of already existing KB.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 14056 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Summarize \arg{}fromKBName\lisp{} \arg{}toKBName\lisp{} \arg{}assocKBNames\lisp{} \arg{}namedObjectsOnly\lisp{})\rm{}}{Method of KBMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Incorporate all objects of \arg{}fromKBName\rm{} with assocKB in \arg{}assocKBNames\rm{} (or all if \arg{}assocKBNames\rm{}=\lisp{}NIL\rm{}) into new KB \arg{}toKBName\rm{}.  If \arg{}namedObjectsOnly\rm{}=\lisp{}T\rm{}, then only copies over all those entities referred to by a name or by a named object directly or indirectly.  This latter feature provides a mechanism for garbage collection.


\parshape 1    0
pt  462pt {}











\vskip10pt

\bf{}\noindent\save0\hbox{9.22}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class EnvironmentMeta

\rm{}\penalty 2000
{\send1{(KBGUTS.IM;3 14537 \count0)}}\penalty 2000
\mark{The Class EnvironmentMeta}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip 10pt
{\send1{(KBGUTS.IM;3 14588 \count0)}}\formatdef{462pt}{\lisp{}EnvironmentMeta\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}

Methods:



\vskip 10pt
{\send1{(KBGUTS.IM;3 14704 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Cleanup)\rm{}}{Method of EnvironmentMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Write updates for all open environments.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 14893 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} Close \arg{}leaveKBattachedFlg\lisp{})\rm{}}{Method of EnvironmentMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Close all the open environments.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KBGUTS.IM;3 15038 \count0)}}\formatdef{462pt}{\lisp{}({\char'137} \arg{}self\lisp{} OpenFiles)\rm{}}{Method of EnvironmentMeta}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Returns a list of the open files for all open Environments.


\parshape 1    0pt  462pt {}





















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{10}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}INTRODUCTION TO RULE-ORIENTED PROGRAMMING IN LOOPS

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 132 \count0)}}\penalty 2000
\mark{INTRODUCTION TO RULE-ORIENTED PROGRAMMING IN LOOPS}
\penalty 2000
\vskip10pt
\penalty 2000
The core of decision-making expertise in many kinds of problem solving can be expressed succinctly in terms of rules.  The following sections describe facilities in Loops for representing rules, and for organizing knowledge-based systems with rule-oriented programming.  The Loops rule language provides an experimental framework for developing knowledge-based systems.  The rule language and programming environment are integrated with the object-oriented, data-oriented, and procedure-oriented parts of Loops.

Rules in Loops are organized into production systems (called RuleSets) with specified control structures for selecting and executing the rules.  The work space for RuleSets is an arbitrary Loops object.

Decision knowledge can be factored from control knowledge to enhance the perspicuity of rules.  The rule language separates decision knowledge from meta-knowledge such as control information, rule descriptions, debugging instructions, and audit trail descriptions.  An audit trail records inferential support in terms of the rules and data that were used.  Such trails are important for knowledge-based systems that must be able to account for their results.  They are also essential for guiding belief revision in programs that need to reason with incomplete information.





\vskip10pt

\bf{}\noindent\save0\hbox{10.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Introduction

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 1483 \count0)}}\penalty 2000
\mark{Introduction}
\penalty 2000
\vskip10pt
\penalty 2000
Production rules have been used in expert systems to represent decision-making knowledge for many kinds of problem-solving.  Such rules (also called \sl{}if-then\rm{} rules) specify actions to be taken when certain conditions are satisfied.  Several rule languages (e.g., \lisp{}OPS5\rm{} [Forgy81], \lisp{}ROSIE\rm{} [Fain81], \lisp{}AGE\rm{} [Aiello81]) have been developed in the past few years and used for building expert systems.  The following sections describe the concepts and facilities for rule-oriented programming in Loops.

Loops has the following major features for rule-oriented programming:



\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(1)\hskip0pt plus 1000pt minus 1000pt}Rules in Loops are organized into ordered sets of rules (called RuleSets) with specified control structures for selecting and executing the rules.  Like subroutines, RuleSets are building blocks for organizing programs hierarchically.  


\parshape 1    0pt  462pt {}

\vskip 10pt

\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(2)\hskip0pt plus 1000pt minus 1000pt}The work space for rules in Loops is an arbitrary Loops object.  The names of the instance variables provide a name space for variables in the rules.


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(3)\hskip0pt plus 1000pt minus 1000pt}Rule-oriented programming is integrated with object-oriented, data-oriented, and procedure-oriented programming in Loops.  


\parshape 1    0
pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(4)\hskip0pt plus 1000pt minus 1000pt}RuleSets can be invoked in several ways:  In the object-oriented paradigm, they can be invoked as methods by sending messages to objects.  In the data-oriented paradigm, they can be invoked as a side-effect of fetching or storing data in active values.  They can also be invoked directly from LISP programs.  This integration makes it convenient to use the other paradigms to organize the interactions between RuleSets.


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(5)\hskip0pt plus 1000pt minus 1000pt}RuleSets can also be invoked from rules either as predicates on the LHS of rules, or as actions on the RHS of rules.  This provides a way for RuleSets to control the execution of other RuleSets.    



\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(6)\hskip0pt plus 1000pt minus 1000pt}Rules can automatically leave an audit trail.  An audit trail is a record of inferential support in terms of rules and data that were used.  Such trails are important for programs that must be able to account for their results.  They can also be used to guide belief revision in programs that must reason with incomplete information.     


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32
pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(7)\hskip0pt plus 1000pt minus 1000pt}Decision knowledge can be separated from control knowledge to enhance the perspicuity of rules.  The rule language separates decision knowledge from meta-knowledge such as control information, rule descriptions, debugging instructions, and audit trail descriptions.


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(8)\hskip0pt plus 1000pt minus 1000pt}The invocation of RuleSets can also be organized in terms of tasks, that can be executed, suspended, and restarted.  Using task primitives it is convenient to specify many varieties of agenda-based control mechanisms.


\parshape 1    0pt  462pt {}

\vskip 10pt

\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(9)\hskip0pt plus 1000pt minus 1000pt}The rule language provides a concise syntax for the most common operations.


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(10)\hskip0pt plus 1000pt minus 1000pt}There is a fast and efficient compiler for translating RuleSets into Interlisp functions.


\parshape 1    0
pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(11)\hskip0pt plus 1000pt minus 1000pt}Loops provides facilities for debugging rule-oriented programs.


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(12)\hskip0pt plus 1000pt minus 1000pt}The rule language is being extended to support concurrent processing.



\parshape 1    0pt  462pt {}


The following sections are organized as follows:  This section outlines the basic concepts of rule-oriented programming in Loops.  It contains many examples that illustrate techniques of rule-oriented programming.  The next section describes the rule syntax.  The next section discusses the facilities for creating, editing, and debugging RuleSets in Loops.  









\vskip10pt

\bf{}\noindent\save0\hbox{10.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Basic Concepts

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 5018 \count0)}}\penalty 2000
\mark{Basic Concepts}
\penalty 2000
\vskip10pt
\penalty 2000
Rules express the conditional execution of actions.  They are important in programming because they can capture the core of decision-making for many kinds of problem-solving.  Rule-oriented programming in Loops is intended for applications to expert and knowledge-based systems.

The following sections outline some of the main concepts of rule-oriented programming.  Loops provides a special language for rules because of their central role, and because special facilities can be associated with rules that are impractical for procedural programming languages.  For example, Loops can save specialized audit trails of rule execution.  Audit trails are important in knowledge systems that need to explain their conclusions in terms of the knowledge used in solving a problem.  This capability is essential in the development of large knowledge-intensive systems, where a long and sustained effort is required to create and validate knowledge bases.  Audit trails are also important for programs that do non-monotonic reasoning.  Such programs must work with incomplete information, and must be able to revise their conclusions in response to new information.  









\vskip10pt

\bf{}\noindent\save0\hbox{10.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Organizing a Rule-Oriented Program

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 6313 \count0)}}\penalty 2000
\mark{Organizing a Rule-Oriented Program}
\penalty 2000
\vskip10pt
\penalty 2000
In any programming paradigm, it is important to have an organizational scheme for composing large systems from smaller ones.  Stated differently, it is important to have a method for partitioning large programs into nearly-independent and manageably-sized pieces.  In the procedure-oriented paradigm, programs are decomposed into procedures.  In the object-oriented paradigm, programs are decomposed into objects.  In the rule-oriented paradigm, programs are decomposed into \sl{}RuleSets\rm{}.{\send1{(RULESINTRO.IM;4 6821 \count0)}}  A Loops program that uses more than one programming paradigm is factored across several of these dimensions.




\vskip 10pt
{\send1{(RULESINTRO.IM;4 6974 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}RuleSet Name: CheckWashingMachine;
WorkSpace Class: WashingMachine;
Control Structure: while1 ;
While Condition: ruleApplied;

(* What a consumer should do when a washing machine fails.)

      IF .Operational THEN (STOP T 'Success 'Working);

      IF load>1.0 THEN .ReduceLoad;

      IF {\char'176}pluggedInTo THEN .PlugIn;

{\char'173}1{\char'175}    IF pluggedInTo:voltage=0 THEN breaker.Reset;

{\char'173}1{\char'175}    IF pluggedInTo:voltage<110 THEN {\char'44}PGE.Call;

{\char'173}1{\char'175}    THEN dealer.RequestService;

{\char'173}1{\char'175}    THEN manufacturer.Complain; 

{\char'173}1{\char'175}    THEN {\char'44}ConsumerBoard.Complain;

{\char'173}1{\char'175}    THEN (STOP T 'Failed 'Unfixable);\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46
pt  416pt {}Figure 13.   RuleSet of consumer instructions for testing a washing machine.  The work space for the RuleSet is a Loops object of the class \lisp{}WashingMachine\rm{}.  The control structure \lisp{}While1\rm{} loops through the rules trying an escalating sequence of actions, starting again at the beginning if some rule is applied.  Some rules, called one-shot rules, are executed at most once.  These rules are indicated by the preceding one in braces.    


\parshape 1    0pt  462pt {}


There are three approaches to organizing the invocation of RuleSets in Loops:

\sl{}Procedure-oriented Approach.\rm{}  This approach is analogous to the use of subroutines in procedure-oriented programming.  Programs are decomposed into RuleSets that call each other and return values when they are finished.  \sl{}SubRuleSets\rm{}{\send1{(RULESINTRO.IM;4 8370 \count0)}} can be invoked from multiple places.  They are used to simplify the expression in rules of complex predicates, generators, and actions. 

\sl{}Object-oriented Approach.\rm{}  In this approach, RuleSets are installed as methods for objects.  They are invoked as methods when messages are sent to the objects.  The method RuleSets are viewed analogously to other procedures that implement object message protocols.  The value computed by the RuleSet is returned as the value of the message sending operation.  

\sl{}Data-oriented Approach.\rm{}  In this approach, RuleSets are installed as access functions in active values.  A RuleSet in an active value is invoked when a program gets or puts a value in the Loops object.  As with active values with Lisp functions for the \sl{}getFn\rm{} or \sl{}putFn\rm{}, these RuleSet active values can be triggered by any Loops program, whether rule-oriented or not.  

These approaches for organizing RuleSets can be combined to control the interactions between bodies of decision-making knowledge expressed in rules.









\vskip10pt

\bf{}\noindent\save0\hbox{10.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Control Structures for Selecting Rules

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 9568 \count0)}}\penalty 2000
\mark{Control Structures for Selecting Rules}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets in Loops consist of an ordered list of rules and a control structure.  Together with the contents of the rules and the data, a RuleSet control structure determines which rules are executed.  Execution is determined by the contents of rules in that the conditions of a rule must be satisfied for it to be executed.  Execution is also controlled by data in that different values in the data allow different rules to be satisfied.  Criteria for iteration and rule selection are specified by a RuleSet control structure.  There are two primitive control structures for RuleSets in Loops which operate as follows:  



\vskip 10pt
{\send1{(RULESINTRO.IM;4 10248 \count0)}}\formatdef{462pt}{\lisp{}Do1\rm{}}{RuleSet Control Structure}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent The first rule in the RuleSet whose conditions are satisfied is executed.  The value of the RuleSet is the value of the rule.  If no rule is executed, the RuleSet returns \lisp{}NIL\rm{}.

The \lisp{}Do1\rm{} control structure is useful for specifying a set of mutually exclusive actions, since at most one rule in the RuleSet will be executed for a given invocation.  When a RuleSet contains rules for specific and general situations, the specific rules should be placed before the general rules.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESINTRO.IM;4 10799 \count0)}}\formatdef{462pt}{\lisp{}DoAll\rm{}}{RuleSet Control Structure}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Starting at the beginning of the RuleSet, every rule is executed whose conditions are satisfied.  The value of the RuleSet is the value of the last rule executed.  If no rule is executed, the RuleSet returns \lisp{}NIL\rm{}.

The \lisp{}DoAll\rm{} control structure is useful when a variable number of additive actions are to be carried out, depending on which conditions are satisfied.  In a single invocation of the RuleSet, all of the applicable rules are invoked.


\parshape 1    0pt  462pt {}


figure X.X illustrates the use of a \lisp{}Do1\rm{} control structure to specify three mutually exclusive actions.




\vskip 10pt
{\send1{(RULESINTRO.IM;4 11442 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}RuleSet Name: SimulateWashingMachine;
WorkSpace Class: WashingMachine;
Control Structure: Do1 ;

(* Rules for controlling the wash cycle of a washing machine.)

   IF controlSetting='RegularFabric 
   THEN .Fill .Wash .Pause .SpinAndDrain
        .SprayAndRinse .SpinAndDrain
        .Fill .DeepRinse .Pause .DampDry;

   IF controlSetting='PermanentPress
   THEN .Fill .Wash .Pause .SpinAndPartialDrain
        .FillCold .SpinAndPartialDrain
        .FillCold .Pause .SpinAndDrain
        .FillCold .DeepRinse .Pause .DampDry;

   IF controlSetting='DelicateFabric 
   THEN .Fill .Soak1 .Agitate .Soak4 .Agitate
        .Soak1 .SpinAndDrain .SprayAndRinse
        .SpinAndDrain .Fill .DeepRinse .Pause .DampDry;\par}\rm{}




\parshape 1    0
pt  462pt {}\parshape 1   46pt  416pt {}Figure 14.   Rules to simulate the control of the wash cycle of a washing machine.  These rules illustrate the use of the \lisp{}Do1\rm{} control structure to select one of three mutually exclusive actions.  These rules were abstracted from [Maytag] for the Maytag A510 washing machine.    


\parshape 1    0pt  462pt {}


There are two control structures in Loops that specify iteration in the execution of a RuleSet.  These control structures use an explicit while-condition associated with the RuleSet.  They are direct extensions of the two primitive control structures above.  



\vskip 10pt
{\send1{(RULESINTRO.IM;4 12794 \count0)}}\formatdef{462pt}{\lisp{}While1\rm{}}{RuleSet Control Structure}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent This is a cyclic version of \lisp{}Do1\rm{}.  If the while-condition is satisfied, the first rule is executed whose conditions are satisfied.  This is repeated as long as the while condition is satisfied or until a \lisp{}Stop\rm{} statement or transfer call is executed (see page X.XX).  The value of the RuleSet is the value of the last rule that was executed, or \lisp{}NIL\rm{} if no rule was executed.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESINTRO.IM;4 13278 \count0)}}\formatdef{462pt}{\lisp{}WhileAll\rm{}}{RuleSet Control Structure}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent This is a cyclic version of \lisp{}DoAll\rm{}.  If the while-condition is satisfied, every rule is executed whose conditions are satisfied.  This is repeated as long as the while condition is satisfied or until a \lisp{}Stop\rm{} statement is executed.  The value of the RuleSet is the value of the last rule that was executed, or \lisp{}NIL\rm{} if no rule was executed. 


\parshape 1    0pt  462pt {}


The {\lquotes}while-condition{\rquotes} is specified in terms of the variables and constants accessible from the RuleSet.  The constant \lisp{}T\rm{} can be used to specify a RuleSet that iterates forever (or until a \lisp{}Stop\rm{} statement or transfer is executed).  The special variable \lisp{}ruleApplied\rm{}{\send1{(RULESINTRO.IM;4 13946 \count0)}} is used to specify a RuleSet that continues as long as some rule was executed in the last iteration.  figure X.X illustrates a simple use of the \lisp{}WhileAll\rm{} control structure to specify a sensing{\char'57}acting feedback loop for controlling the filling of a washing machine tub with water.




\vskip 10pt
{\send1{(RULESINTRO.IM;4 14272 \count0)}}\parshape 1   46
pt  416pt {}

\lisp{}{\nofill{}RuleSet Name: FillTub;
WorkSpace Class: WashingMachine;
Control Structure: WhileAll ;
Temp Vars: waterLimit;
While Cond: T;

   (* Rules for controlling the filling of a washing machine
      tub with water.)

{\char'173}1!{\char'175} IF loadSetting='Small THEN waterLimit{\char'137}10;
{\char'173}1!{\char'175} IF loadSetting='Medium THEN waterLimit{\char'137}13.5;
{\char'173}1!{\char'175} IF loadSetting='Large THEN waterLimit{\char'137}17;
{\char'173}1!{\char'175} IF loadSetting='ExtraLarge THEN waterLimit{\char'137}20;

   (* Respond to a change of temperature setting at any time.)

     IF temperatureSetting='Hot
     THEN HotWaterValve.Open ColdWaterValve.Close;

     IF temperatureSetting='Warm
     THEN HotWaterValve.Open ColdWaterValve.Open;

     IF temperatureSetting='Cold
     THEN ColdWaterValve.Open HotWaterValve.Close;

   (* Stop when the water reaches its limit.)

     IF waterLevelSensor.Test >= waterLimit
     THEN HotWaterValve.Close ColdWaterValve.Close
          (Stop T 'Done 'Filled);\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 15.   Rules to simulate filling the tub in a washing machine with water.  These rules illustrate the use of the \lisp{}WhileAll\rm{} control structure to specify an infinite sense-act loop that is terminated by a \lisp{}Stop\rm{} statement.  These rules were abstracted from [MayTag].


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{10.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}One-Shot Rules

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 15601 \count0)}}\penalty 2000
\mark{One-Shot Rules}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(RULESINTRO.IM;4 15622 \count0)}}


One of the design objectives of Loops is to clarify the rules by factoring out control information whenever possible.  This objective is met in part by the declaration of a control structure for RuleSets.


Another important case arises in cyclic control structures which some of the rules should be executed only once.  This was illustrated in the WashingMachine example in figure X.X where we wanted to prevent the RuleSet from going into an infinite loop of resetting the breaker, when there was a short circuit in the Washing Machine.  Such rules are also useful for initializing data for RuleSets as in the example in figure X.X.

In the absence of special syntax, it would be possible to encode the information that a rule is to be executed only once as follows:



\lisp{}{\nofill{}Control Structure: While1
Temporary Vars:  triedRule3;
...
IF {\char'176}triedRule3 \arg{}condition\sub{1}\lisp{} \arg{}condition\sub{2}\lisp{} THEN triedRule3{\char'137}T \arg{}action\sub{1}\lisp{};\par}\rm{}



In this example, the variable \lisp{}triedRule3\rm{} is used to control the rule so that it will be executed at most once in an invocation of a RuleSet.  However, the prolific use of rules with such control clauses in large systems has led to the common complaint that control clauses in rule languages defeat the expressiveness and conciseness of the rules.  For the case above, Loops provides a shorthand notation as follows:



\lisp{}{\nofill{}{\char'173}1{\char'175}	IF \arg{}condition\sub{1}\lisp{} \arg{}condition\sub{2}\lisp{} THEN \arg{}action\sub{1}\lisp{};\par}\rm{}



The brace notation means exactly the same thing in the example above, but it more concisely and clearly indicates that the rule executes only once.  These rules are called {\lquotes}one shot{\rquotes} or {\lquotes}execute-once{\rquotes} rules.

In some cases, it is desired not only that a rule be executed at most once, but that it be tested at most once.  This corresponds to the following:



\lisp{}{\nofill{}Control Structure: While1
Temporary Vars:  triedRule3;
...
IF {\char'176}triedRule3 triedRule3{\char'137}T \arg{}condition\sub{1}\lisp{} \arg{}condition\sub{2}\lisp{} THEN \arg{}action\sub{1}\lisp{};\par}\rm{}



In this case, the rule will not be tried more than once even if some of the conditions fail the first time that it is tested.  The Loops shorthand for these rules (pronounced {\lquotes}one shot bang{\rquotes}) is



\lisp{}{\nofill{}{\char'173}1!{\char'175}	IF \arg{}condition\sub{1}\lisp{} \arg{}condition\sub{2}\lisp{} THEN \arg{}action\sub{1}\lisp{};\par}\rm{}



These rules are called {\lquotes}try-once{\rquotes} rules.

The two kinds of one-shot rules are our first examples of the use of meta-descriptions preceding the rule body in braces.  See page X.XX for information on using meta-descriptions for describing the creation of audit trails.









\vskip10pt

\bf{}\noindent\save0\hbox{10.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Task-Based Control for RuleSets

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 18341 \count0)}}\penalty 2000
\mark{Task-Based Control for RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
* * * Tasks are Not Fully Implemented Yet * * *

Flexible control of reasoning is generally recognized as critical to the success of recent problem-solving programs.  Examples of flexible control are:



\vskip 10pt

\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(1)\hskip0pt plus 1000pt minus 1000pt}In planning and design tasks, it is important to generate multiple alternatives.  These alternatives may be carried to different degrees of completion, depending on success, resource limitations, and information gained during a problem-solving process.  In some cases, an alternative may be temporarily set aside, only to be revived later in light of new information.


\parshape 1    0pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(2)\hskip0pt plus 1000pt minus 1000pt}In analysis tasks, it is important to pursue multiple hypotheses in parallel.  As evidence and conclusions accumulate, some hypotheses may be abandoned but revived later.


\parshape 1    0
pt  462pt {}

\vskip 10pt
\parshape 1   32pt  430pt {}\noindent\hbox to 0pt{\hskip-32pt{}(3)\hskip0pt plus 1000pt minus 1000pt}Search and discovery tasks can be organized as opportunistic best-first searches.  At each step only the most promising avenues are pursued.  As some avenues fail to work out and new information accumulates, the other avenues can be re-evaluated and sometimes raised in priority.


\parshape 1    0pt  462pt {}



These examples require the ability (1) to suspend parts of a computation with the possibility of restarting them later, and (2) to reason about the control of computational resources.    

Loops provides a set of language features to support these capabilities, based on the representation of the execution of a RuleSet as a \sl{}Task\rm{}.{\send1{(RULESINTRO.IM;4 19784 \count0)}}  A Task is a Loops object with much the same structure as an item in an agenda (see figure X.X).  It represents the RuleSet being invoked, the data on which it is operating, and the status of its execution.




\vskip 10pt
{\send1{(RULESINTRO.IM;4 20039 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}RepairTask5:

ruleNumber:   NIL doc (* Number of the next rule to be executed.
                         Used for doNext and cycleNext.)
rs:           {\char'43}{\char'44}RepairWashingMachine
                  doc (* RuleSet that was invoked.)
self:         {\char'43}&(FixitJob "uid1")
                  doc (* work space given to the RuleSet.)
value:        {\char'43}&(MotorBrushes "uid2")
                  doc (* value returned by the RuleSet)
status:       Suspended
                  doc (* Execution status.  Examples: Started,
                         Done, Aborted, Suspended.)
reason:       TooExpensive
                  doc (* Reason for the status.  Examples: Success,
                         NoSpace, Blocked)
caller:       {\char'43}{\char'44}(RuleSet "uid3")
                  doc (* Caller of the RuleSet.)
priority:     300\par}\rm{}





\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 16.   An example of a Task object.  This Task could have been created for an invocation of the RuleSet in figure X.X.  The Task records the RuleSet, its data, and its execution status.  The instance variable \lisp{}ruleNumber\rm{} is used only for the control structures \lisp{}DoNext\rm{} and \lisp{}CycleNext\rm{} as described in the next section.  The instance variable priority was created in response to the Task Vars declaration in the RuleSet.    


\parshape 1    0pt  462pt {}



figure X.X illustrates a RuleSet for a task that can be suspended.  This RuleSet represents part of the behavior of a washing machine repair man.  The repair task may be suspended after it has started on a particular \lisp{}FixitJob\rm{} object if the failure is not diagnosed or is too expensive.



\vskip 10pt
{\send1{(RULESINTRO.IM;4 21688 \count0)}}\parshape 1   46
pt  416pt {}

\lisp{}{\nofill{}RuleSet Name: RepairWashingMachine;
WorkSpace Class: FixitJob;
Compiler Options: S ;  (* S for Task Stepping.)
Control Structure: doAll ;
Task Vars: priority;

(* Rules for washing machine repair.)

{\char'173}1{\char'175}   priority{\char'137}300;
...
{\char'173}1{\char'175}   IF {\char'176}(replacementPart{\char'137}motor.FindBrokenPart) 
   THEN (STOP T 'Suspended 'NoDiagnosis);

   IF replacementPart.Availability='NotInTruck hoursLimit < 1
   THEN (STOP badPart 'Suspended 'UnavailablePart);

   IF replacementPart:cost > dollarLimit 
   THEN (STOP badPart 'Suspended 'TooExpensive);
...\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 17.   A suspendable Task.  This RuleSet characterizes part of the behavior of a repair man of washing machines.  The Stop statements specify how the RuleSet may report failure after it has been started on a particular \lisp{}FixitJob\rm{}.  Information in task variables (like priority) are saved in the Task record.  In this example, the machine failure may not be diagnosed or may be too expensive to fix.


\parshape 1    0pt  462pt {}


figure X.X illustrates a RuleSet for controlling suspendable tasks.  This RuleSet represents part of the behavior of the owner of a washing machine repair business.  This RuleSet may restart any suspended task by the repairman RuleSet after getting more information about the customer.




\vskip 10pt
{\send1{(RULESINTRO.IM;4 23000 \count0)}}
\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}RuleSet Name: RePlanRepairWork;
WorkSpace Class: JobSchedule;
Control Structure: cycleAll ;
RuleVars: currentTask customer substitutePart;

(* Sample Rules -- part of the behavior of a manager of a
   Washing Machine repair business.)

...
   IF currentTask:status='Success 
   THEN (STOP T 'Done 'Success);

   IF currentTask:reason='UnavailablePart
      substitutePart{\char'137}expert.AskForSubstitutePart
   THEN currentTask:self:replacementPart{\char'137}substitutePart
        (Start currentTask);

   IF customer:category='VIP
      currentTask:reason='TooExpensive
   THEN currentTask:self:dollarLimit {\char'137} VIP:dollarLimit
        currentTask:priority {\char'137} 100
        (Start currentTask);
...\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46pt  416pt {}Figure 18.   Control of Tasks.  This RuleSet characterizes part of the behavior of the manager of a washing machine repair business.  When a repair task fails, the manager RuleSet may change some resource limits and start the repair task going again (e.g., if the customer is a \lisp{}VIP\rm{}).


\parshape 1    0
pt  462pt {}


Loops has facilities for creating Task objects, starting and waiting for tasks, stepping and suspending Tasks.  Task variables are used for saving state information.  Distinct Tasks can refer to distinct invocations of the same RuleSet in different states of execution.  The language features supporting Tasks are described later.









\vskip10pt

\bf{}\noindent\save0\hbox{10.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Control Structures for Generators

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 24478 \count0)}}\penalty 2000
\mark{Control Structures for Generators}
\penalty 2000
\vskip10pt
\penalty 2000
Since Tasks represent suspended processes with local state, it is natural to use them for describing generators.  For the concise specification of generators, two additional control structures have been provided in Loops.  To use these control structures, a Task is first created that associates a RuleSet and a work space.  The Task is then invoked repeatedly.  At each invocation at most one rule is activated and the Task records which rule was activated.  At the next invocation, the search for the next rule to apply starts with the rule following the rule that was last executed.




\vskip 10pt
{\send1{(RULESINTRO.IM;4 25128 \count0)}}\formatdef{462pt}{\lisp{}DoNext\rm{}}{RuleSet Control Structure}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent At each invocation of the Task, the next rule is executed whose conditions are satisfied.  The value of the RuleSet is the value of the executed rule, or \lisp{}NIL\rm{} if no rule was executed.  After the last rule of the RuleSet has been tried, the Task will always return \lisp{}NIL\rm{}.

This control structure is convenient for specifying a generator of a limited number of items.  At each invocation, the remaining rules are tried until the next item is generated.  The generator returns \lisp{}NIL\rm{} after all of the rules have been tried.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESINTRO.IM;4 25732 \count0)}}\formatdef{462pt}{\lisp{}WhileNext\rm{}}{RuleSet Control Structure}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent At each invocation of the Task, the generator first checks whether the while condition of the RuleSet is satisfied.  If yes, then the next rule is executed whose conditions are satisfied.  The rules can be visualized as forming a circle, so that after the last rule of the RuleSet has been tried, the generator goes back to the beginning.  During a single invocation, no rule is tried more than once and the while-condition is tested only once at the beginning of the Step.  The value of the RuleSet is the value of the last rule executed or \lisp{}NIL\rm{} if no rule was executed. 

This control structure is convenient for specifying a generator that repeats itself periodically, and which has an extra condition that is factored from all of the rules.



\parshape 1    0pt  462pt {}


If a RuleSet with one of these control structures is invoked directly (instead of through a Task), its behavior is equivalent to that of a \lisp{}Do1\rm{} control structure.

The variable \lisp{}ruleApplied\rm{},{\send1{(RULESINTRO.IM;4 26713 \count0)}} which can be used in the while-condition of \lisp{}While1\rm{} and \lisp{}WhileAll\rm{} control structures, is not meaningful with the \lisp{}WhileNext\rm{} control structure since at most one rule is applied in a given invocation. 










\vskip10pt

\bf{}\noindent\save0\hbox{10.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Saving an Audit Trail of Rule Invocation

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 27095 \count0)}}\penalty 2000
\mark{Saving an Audit Trail of Rule Invocation}
\penalty 2000
\vskip10pt
\penalty 2000
A basic property of knowledge-based systems is that they use knowledge to infer new facts from older ones.  (Here we use the word {\lquotes}facts{\rquotes} as a neutral term, meaning any information derived or given, that is used by a reasoning system.)  Over the past few years, it has become evident that reasoning systems need to keep track not only of their conclusions, but also of their reasoning steps.  Consequently, the design of such systems has become an active research area in AI.  The audit trail facilities of Loops support experimentation with systems that can not only use rules to make inferences, but also keep records of the inferential process itself.




\vskip10pt

\bf{}\noindent\save0\hbox{10.8.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Motivations and Applications

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 27841 \count0)}}\penalty 2000
\mark{Motivations and Applications}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}Debugging.\rm{}  In most expert systems, knowledge bases are developed over time and are the major investment.  This places a premium on the use of tools and methods for identifying and correcting bugs in knowledge bases.  By connecting a system's conclusions with the knowledge that it uses to derive them, audit trails can provide a substantial debugging aid.  Audit trails provide a focused means of identifying potentially errorful knowledge in a problem solving context.    

\sl{}Explanation Facilities.\rm{}  Expert systems are often intended for use by people other than their creators, or by a group of people \sl{}pooling\rm{} their knowledge.  An important consideration in validating expert systems is that reasoning should be \sl{}transparent\rm{}, that is, that a system should be able to give an account of its reasoning process.  Facilities for doing this are sometimes called \sl{}explanation systems\rm{} and the creation of powerful explanation systems is an active research area in AI and cognitive science.  The audit trail mechanism provides an essential computational prerequisite for building such systems.   

\sl{}Belief Revision.\rm{}  Another active research area is the development of systems that can {\lquotes}change their minds{\rquotes}.  This characteristic is critical for systems that must reason from incomplete or errorful information.  Such systems get leverage from their ability to make assumptions, and then to recover from bad assumptions by efficiently reorganizing their beliefs as new information is obtained.  Research in this area ranges from work on non-monotonic logics, to a variety of approaches to belief revision.  The facilities in the rule language make it convenient to use a user-defined calculus of belief revision, at whatever level of abstraction is appropriate for an application. 









\vskip10pt

\bf{}\noindent\save0\hbox{10.8.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Overview of Audit Trail Implementation

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 29797 \count0)}}\penalty 2000
\mark{Overview of Audit Trail Implementation}
\penalty 2000
\vskip10pt
\penalty 2000
When \sl{}audit mode\rm{}{\send1{(RULESINTRO.IM;4 29838 \count0)}} is specified for a RuleSet, the compilation of assignment statements on the right-hand sides of rules is altered so that audit records are created as a side-effect of the assignment of values to instance variables.  Audit records are Loops objects, whose class is specified in RuleSet declarations.  The audit records are connected with associated instance variables through the value of the \lisp{}reason\rm{}{\send1{(RULESINTRO.IM;4 30263 \count0)}} properties of the variables.  

Audit descriptions can be associated with a RuleSet as a whole, or with specific rules.  Rule-specific audit information is specified in a property-list format in the meta-description associated with a rule.  For example, this can include \sl{}certainty factor\rm{} information, categories of inference, or categories of support.  Rule-specific information overrides RuleSet information. 

During rule execution in audit mode, the audit information is evaluated after the rule's LHS has been satisfied and before the rule's RHS is applied.  For each rule applied, a single audit record is created and then the audit information from the property list in the rule's meta-description is put into the corresponding instance variables of the audit record.  The audit record is then linked to each of the instance variables that have been set on the RHS of the rule by way of the \lisp{}reason\rm{}{\send1{(RULESINTRO.IM;4 31198 \count0)}} property of the instance variable.

Additional computations can be triggered by associating active values with either the audit record class or with the instance variables. For example, active values can be specified in the audit record classes in order to define a uniform set of side-effects for rules of the same category.  In the following example, such an active value is used to carry out a {\lquotes}certainty factor{\rquotes} calculation.










\vskip10pt

\bf{}\noindent\save0\hbox{10.8.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}An Example of Using Audit Trails

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 31780 \count0)}}\penalty 2000
\mark{An Example of Using Audit Trails}
\penalty 2000
\vskip10pt
\penalty 2000
The following example illustrates one way to use the audit trail facilities.  figure X.X illustrates a RuleSet which is intended to capture the decisions for evaluating the potential purchase of a washing machine.  As with any purchasing situation, this one includes the difficulty of incomplete information about the product.  The meta-descriptions for the rules categorize them in terms of the \sl{}basis of belief\rm{} (fact or estimate) and a \sl{}certainty factor\rm{} that is supposed to measure the {\lquotes}implication power{\rquotes} of the rule.  (Realistic belief revision systems are usually more sophisticated than this example.)



\vskip 10pt
{\send1{(RULESINTRO.IM;4 32467 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}RuleSet Name: EvaluateWashingMachine;
WorkSpace Class: EvaluationReport;
Control Structure: doAll ;
Audit Class: CFAuditRecord ;
Compiler Options: A;        

(* Rules for evaluating a potential washing machine for a purchase.)

   ...

   {\char'173}(basis{\char'137}'Fact cf{\char'137}1){\char'175}
   IF buyer:familySize>2  machine:capacity<20
   THEN suitability{\char'137}'Poor;

   {\char'173}(basis{\char'137}'Fact cf{\char'137}.8){\char'175}
   reliability{\char'137}({\char'137} {\char'44}ConsumerReports GetFacts machine);

   {\char'173}(basis{\char'137}'Estimate cf{\char'137}.4){\char'175}
   IF {\char'176}reliability THEN reliability{\char'137}.5;
   ...\par}\rm{}




\parshape 1    0pt  462pt {}\parshape 1   46
pt  416pt {}Figure 19.   RuleSet for evaluating a washing machine for purchase.  Like many kinds of problems, a purchase problem requires making decisions in the absence of complete information.  For example, in this RuleSet the reliability of the washing machine is estimated to be .5 in the absence of specific information from \lisp{}ConsumerReports\rm{}.  The meta-description in braces in front of each rule characterizes the rule in terms of a \lisp{}cf\rm{} (certainty factor) and a \lisp{}basis\rm{} (basis of belief).  Within the braces, the variable on the left of the assignment statement is always interpreted as meaning a variable in the audit record, and the variables on the right are always interpreted as variables accessible within the RuleSet.  This makes it straightforward to experiment with user-defined audit trails and experimental methods of belief revision.


\parshape 1    0pt  462pt {}

The result of running the RuleSet is an evaluation report for each candidate machine.  Since the RuleSet was run in audit mode, each entry in the evaluation report is tagged with a reason that points to an audit record.  figure X.X illustrates the evaluation report for one machine and one of its audit records.



\vskip 10pt
{\send1{(RULESINTRO.IM;4 34215 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}EvaluationReport "uid1"
expense:       510
suitability:    Poor  cc 1 reason ...
reliability:       .5 cc .6 reason "uid2"
...
                                                           

AuditRec "uid2"
rule:          "uid3"
basis:          Estimate;
cf:            {\char'43}(.4 NIL PutCumulativeCertainty)
   ...\par}\rm{}




\parshape 1    0pt  462pt {}
\parshape 1   46pt  416pt {}Figure 20.   Example of an audit trail.  The object for the expense report was prepared by the RuleSet in figure X.X.  In this example, each of the entries in the report has a \lisp{}reason\rm{} and a \lisp{}cc\rm{} (for cumulative certainty) property in addition to the value.  The value of the \lisp{}reason\rm{} properties are \sl{}audit records\rm{}{\send1{(RULESINTRO.IM;4 34916 \count0)}} created as a side effect of running the RuleSet.  The auditing process records the meta-description information of each rule in its audit record.  This information can be used later for generating explanations or as a basis for belief revision.  The auditing process can have side effects.  For example, the active value in the \lisp{}cf\rm{} variable of the audit record performs a computation to maintain a calculated cumulative certainty in the \lisp{}reliability\rm{} variable of the evaluation report. 


\parshape 1    0pt  462pt {}


The result of running the RuleSet is an evaluation report for each candidate machine.  The meta-descriptions for \lisp{}basis\rm{} and \lisp{}cf\rm{} are saved directly in the audit record.  The \sl{}certainty factor\rm{} calculation in this combines information from the audit description with other information already associated with the object.  To do this, the \lisp{}cf\rm{} description triggers an active value inherited by the audit record from its class.  This active value computes a \sl{}cumulative certainty\rm{} in the evaluation report.  (Other variations on this idea would include certainty information descriptive of the premises of the rule.)













\vskip10pt

\bf{}\noindent\save0\hbox{10.9}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Comparison with other Rule Languages

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 36277 \count0)}}\penalty 2000
\mark{Comparison with other Rule Languages}
\penalty 2000
\vskip10pt
\penalty 2000
This section considers the rationale behind the design of the Loops rule language, focusing on ways that it diverges from other rule languages.  In general, this divergence was driven by the following observation:  

\sl{}When a rule is heavy with control information, it obscures the domain knowledge that the rule is intended to convey.
\rm{}

Rules are harder to create, understand, and modify when they contain too much control information.  This observation led us to find ways to factor control information out of the rules. 




\vskip10pt

\bf{}\noindent\save0\hbox{10.9.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Rationale for Factoring Meta-Level Syntax

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 36928 \count0)}}\penalty 2000
\mark{The Rationale for Factoring Meta-Level Syntax}
\penalty 2000
\vskip10pt
\penalty 2000
One of the most striking features of the syntax of the Loops rule language is the factored syntax for meta-descriptions, which provides information about the rules themselves.  Traditional rule languages only factor rules into conditions on the left hand side (LHS) and actions on the right hand side (RHS), without general provisions for meta-descriptions.

Decision knowledge expressed in rules is most perspicuous when it is not mixed with other kinds knowledge, such as control knowledge.  For example, the following rule:



\lisp{}{\nofill{}IF {\char'176}triedRule4 pluggedInTo:voltage=0
THEN triedRule4{\char'137}T breaker.Reset;\par}\rm{}



is more obscure than the corresponding one-shot rule from figure X.X:



\lisp{}{\nofill{}{\char'173}1{\char'175}   IF pluggedInTo:voltage=0 THEN breaker.Reset;\par}\rm{}




which factors the control information (that the rule is to be applied at most once) from the domain knowledge (about voltages and breakers).  In the Loops rule language, a meta-description (MD) is specified in braces in front of the LHS of a rule.  For another example, the following rule from figure X.X:



\lisp{}{\nofill{}{\char'173}(basis{\char'137}'Fact cf{\char'137}.8){\char'175}
IF buyer:familySize>2  machine:capacity<20
THEN suitability{\char'137}'Poor;\par}\rm{}



uses an MD to indicate that the rule has a particular \lisp{}cf\rm{} ({\lquotes}certainty factor{\rquotes}) and \lisp{}basis\rm{} category for belief support.  The MD in this example factors the description of the inference category of the rule from the action knowledge in the rule.  

In a large knowledge-based system, a substantial amount of control information must be specified in order to preclude combinatorial explosions.  Since earlier rule languages fail to provide a means for factoring meta-information, they must either mix it with the domain knowledge or express it outside the rule language.  In the first option, perspecuity is degraded.  In the second option, the transparency of the system is degraded because the knowledge is hidden. 










\vskip10pt

\bf{}\noindent\save0\hbox{10.9.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Rationale for RuleSet Hierarchy

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 39020 \count0)}}\penalty 2000
\mark{The Rationale for RuleSet Hierarchy}
\penalty 2000
\vskip10pt
\penalty 2000
Some advocates of production systems have praised the flatness of traditional production systems, and have resisted the imposition of any organization to the rules.  The flat organization is sometimes touted as making it \sl{}easy to add rules\rm{}.  The argument is that other organizations diminish the power of pattern-directed invocation and make it more complicated to add a rule.  

In designing Loops, we have tended to discount these arguments.  We observe that there is no inherent property of production systems that can make rules additive.  Rather, \sl{}additivity\rm{} is a consequence of the independence of particular sets of rules.  Such independence is seldom achieved in large \sl{}sets\rm{} of rules.  When rules are dependent, rule invocation needs to be carefully ordered.  

Advocates of a flat organization tend to organize large programs as a single very large production system.  In practice, most builders of production systems have found it essential to create groups of rules.

Grouping of rules in flat systems can be achieved in part by using \sl{}context\rm{} clauses in the rules.  Context clauses are clauses inserted into the rules which are used to alter the flow of control by naming the context explicitly.  Rules in the same {\lquotes}context{\rquotes} all contain an extra clause in their conditions that compares the context of the rules with a current context.  Other rules redirect control by switching the current context.  Unfortunately, this approach does not conveniently lend itself to the reuse of groups of rules by different parts of a program.  Although context clauses admit the creation of {\lquotes}subroutine contexts{\rquotes}, they require a user to explicitly program a stack of return locations in cases where contexts are invoked from more than one place.  The decision to use an implicit calling-stack for RuleSet invocation in Loops is another example of the our desire to simplify the rules by factoring out control information.  








\vskip10pt

\bf{}\noindent\save0\hbox{10.9.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Rationale for RuleSet Control Structures

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 41131 \count0)}}\penalty 2000
\mark{The Rationale for RuleSet Control Structures}
\penalty 2000
\vskip10pt
\penalty 2000
Production languages are sometimes described as having a \sl{}recognize-act cycle\rm{}, which specifies how rules are selected for execution.  An important part of this cycle is the \sl{}conflict resolution strategy\rm{}, which specifies how to choose a production rule when several rules have conditions that are satisfied.  For example, the \lisp{}OPS5\rm{} production language [Forgy81] has a conflict resolution strategy (\lisp{}MEA\rm{}) which prevents rules from being invoked more than once, prioritizes rules according to the recency of a change to the data, and gives preference to production rules with the most specific conditions.

In designing the rule language for Loops, we have favored the use of a small number of specialized control structures to the use of a single complex conflict resolution strategy.  In so doing, we have drawn on some control structures in common use in familiar programming languages.  For example, \lisp{}Do1\rm{} is like Lisp's \lisp{}COND\rm{}, \lisp{}DoAll\rm{} is like Lisp's \lisp{}PROG\rm{}, \lisp{}WhileAll\rm{} is similar to \lisp{}WHILE\rm{} statements in many programming languages.  

The specialized control structures are intended for concisely representing programs with different control relationships among the rules.  For example, the \lisp{}DoAll\rm{} control structure is useful for rules whose effects are intended to be additive and the \lisp{}Do1\rm{} control structure is appropriate for specifying mutually exclusive actions.  Without some kind of iterative control structure that allows rules to be executed more than once, it would be impossible to write a simulation program such as the washing machine simulation in figure X.X.  

We have resisted a reductionist argument for having only one control structure for all programming.  For example, it could be argued that the control structure \lisp{}Do1\rm{} is not strictly necessary because any RuleSet that uses \lisp{}Do1\rm{} could be rewritten using \lisp{}DoAll\rm{}.  For example, the rules



\lisp{}{\nofill{}Control Structure: Do1;

IF \arg{}a\sub{1}\lisp{} \arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{1}\lisp{} \arg{}e\sub{1}\lisp{};
IF \arg{}a\sub{2}\lisp{} \arg{}b\sub{2}\lisp{} \arg{}c\sub{2}\lisp{} THEN \arg{}d\sub{2}\lisp{} \arg{}e\sub{2}\lisp{};
IF \arg{}a\sub{3}\lisp{} \arg{}b\sub{3}\lisp{} \arg{}c\sub{3}\lisp{} THEN \arg{}d\sub{3}\lisp{} \arg{}e\sub{3}\lisp{};\par}\rm{}



could be written alternatively as



\lisp{}{\nofill{}Control Structure: DoAll;
Task Vars: firedSomeRule;

IF \arg{}a\sub{1}\lisp{} \arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN firedSomeRule{\char'137}T \arg{}d\sub{1}\lisp{} \arg{}e\sub{1}\lisp{};
IF {\char'176}firedSomeRule \arg{}a\sub{2}\lisp{} \arg{}b\sub{2}\lisp{} \arg{}c\sub{2}\lisp{} THEN firedSomeRule{\char'137}T \arg{}d\sub{2}\lisp{} \arg{}e\sub{2}\lisp{};
IF {\char'176}firedSomeRule \arg{}a\sub{3}\lisp{} \arg{}b\sub{3}\lisp{} \arg{}c\sub{3}\lisp{} THEN firedSomeRule{\char'137}T \arg{}d\sub{3}\lisp{} \arg{}e\sub{3}\lisp{};\par}\rm{}



However, the \lisp{}Do1\rm{} control structure admits a much more concise expression of mutually exclusive actions.  In the example above, the \lisp{}Do1\rm{} control structure makes it possible to abbreviate the rule conditions to reflect the assumption that earlier rules in the RuleSet were not satisfied.  

For some particular sets of rules the conditions are naturally mutually exclusive.  Even for these rules \lisp{}Do1\rm{} can yield additional conciseness.  For example, the rules:



\lisp{}{\nofill{}Control Structure: Do1;

IF  \arg{}a\sub{1}\lisp{}  \arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{1}\lisp{} \arg{}e\sub{1}\lisp{};
IF {\char'176}\arg{}a\sub{1}\lisp{}  \arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{2}\lisp{} \arg{}e\sub{2}\lisp{};
IF {\char'176}\arg{}a\sub{1}\lisp{} {\char'176}\arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{3}\lisp{} \arg{}e\sub{3}\lisp{};\par}\rm{}



can be written as



\lisp{}{\nofill{}Control Structure: Do1;

IF \arg{}a\sub{1}\lisp{} \arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{1}\lisp{} \arg{}e\sub{1}\lisp{};
IF    \arg{}b\sub{1}\lisp{} \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{2}\lisp{} \arg{}e\sub{2}\lisp{};
IF       \arg{}c\sub{1}\lisp{} THEN \arg{}d\sub{3}\lisp{} \arg{}e\sub{3}\lisp{};\par}\rm{}



Similarly it could be argued that the \lisp{}Do1\rm{} and \lisp{}DoAll\rm{} control structures are not strictly necessary because such RuleSets can always be written in terms of \lisp{}While1\rm{} and \lisp{}WhileAll\rm{}.  Following this reductionism to its end, we can observe that every RuleSet could be re-written in terms of \lisp{}WhileAll\rm{}.  









\vskip10pt

\bf{}\noindent\save0\hbox{10.9.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Rationale for an Integrated Programming Environment

\rm{}\penalty 2000
{\send1{(RULESINTRO.IM;4 45378 \count0)}}\penalty 2000
\mark{The Rationale for an Integrated Programming Environment}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets in Loops are integrated with procedure-oriented, object-oriented, and data-oriented programming paradigms.  In contrast to single-paradigm rule systems, this integration has two major benefits.  It facilitates the construction of programs which don't entirely fit the rule-oriented paradigm.  Rule-oriented programming can be used selectively for representing just the appropriate decision-making knowledge in a large program.  Integration also makes it convenient to use the other paradigms to help organize the interactions between RuleSets.  

Using the object-oriented paradigm, RuleSets can be invoked as methods for Loops objects.  figure X.X illustrates the installation of the RuleSet \lisp{}SimulateWashingMachineRules\rm{} to carry out the \lisp{}Simulate\rm{} method for instances of the class \lisp{}WashingMachine\rm{}.  The use of object-oriented paradigm is facilitated by special RuleSet syntax for sending messages to objects, and for manipulating the data in Loops objects.  In addition, RuleSets, work spaces, and tasks are implemented as Loops objects.





\vskip 10pt
{\send1{(RULESINTRO.IM;4 46517 \count0)}}\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}[DEFCLASS WashingMachine 
   (MetaClass Class Edited (* "mjs: 25-Nov-82 16:42")
            doc (* Home appliance for washing clothes.))
   (Supers ElectricalDevice PlumbedDevice CleaningDevice)
   (ClassVariables)
   (InstanceVariables 
      (controlSetting Medium
            doc (* One of Small, Medium, Large, ExtraLarge)) ...)
   (Methods 
      (Fill WashingMachine.Fill doc (* Fill the tub with water.))
      (Wash WashingMachine.Wash doc (* Perform the wash cycle.))
      (Simulate UseRuleSet RuleSet SimulateWashingMachineRules)
	...]\par}\rm{}




\parshape 1    0
pt  462pt {}\parshape 1   46pt  416pt {}Figure 21.   Example of using a RuleSet as a method for object-oriented invocation.  This definition of the class \lisp{}WashingMachine\rm{} specifies that Lisp functions are to be invoked for \lisp{}Fill\rm{} and \lisp{}Wash\rm{} messages.  For example, the Lisp function \lisp{}WashingMachine.Fill\rm{} is to be applied when a \lisp{}Fill\rm{} message is received.  When a \lisp{}Simulate\rm{} message is received, the RuleSet \lisp{}SimulateWashingMachineRules\rm{} is to be invoked with the washing machine as its work space.  \lisp{}Simulate\rm{} messages to invoke the RuleSet may be sent by any Loops program, including other RuleSets.


\parshape 1    0pt  462pt {}


Using the data-oriented paradigm, RuleSets can be installed in active values so that they are triggered by side-effect when Loops programs get or put data in objects.   figure X.X illustrates a RuleSet named \lisp{}CheckOverLoadRules\rm{} which is triggered whenever a program changes the \lisp{}loadSetting\rm{} variable in the \lisp{}WashingMachine\rm{} instance in the figure.  This data-oriented triggering can bd waiting for tasks, stepping and suspending Tasks.  Task variables are used for saving state information.  Distinct Tasks can refer to distinctDEFINSTWashingMachine

{\char'173}TEXT


\lisp{}{\nofill{}(DEFINST WashingMachine (StefiksMaytagWasher "uid2") 
   (controlSetting RegularFabric)
   (loadSetting {\char'43}(Medium NIL RSPut) RSPutFn CheckOverLoadRules)
   (waterLevelSensor "uid3")
]\par}\rm{}


{\char'175}
{\char'173}CAPTION
This instance of the class \lisp{}WashingMachine\rm{} illustrates the invocation of a RuleSet in data-oriented programming.  It specifieds a RuleSet in the active value in the \lisp{}loadSetting\rm{} instance variable.  If any Loops program changes the value of the instance variable \lisp{}loadSetting\rm{}, then the RuleSet \lisp{}OverLoadRules\rm{} is invoked.{\char'175}





















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{11}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}THE RULE LANGUAGE

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 67 \count0)}}\penalty 2000
\mark{THE RULE LANGUAGE}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip10pt

\bf{}\noindent\save0\hbox{11.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Rule Forms

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 120 \count0)}}\penalty 2000
\mark{Rule Forms}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 144 \count0)}}

A rule in Loops describes actions to be taken when specified conditions are satisfied.   A rule has three major parts called the \sl{}left hand side\rm{}{\send1{(RULESLANGUAGE.IM;4 316 \count0)}} (LHS){\send1{(RULESLANGUAGE.IM;4 333 \count0)}} for describing the conditions, the \sl{}right hand side\rm{}{\send1{(RULESLANGUAGE.IM;4 412 \count0)}} (RHS){\send1{(RULESLANGUAGE.IM;4 429 \count0)}} for describing the actions, and the \sl{}meta-description\rm{}{\send1{(RULESLANGUAGE.IM;4 511 \count0)}} (MD){\send1{(RULESLANGUAGE.IM;4 526 \count0)}} for describing the rule itself.  In the simplest case without a meta-description, there are two equivalent syntactic forms:



\lisp{}{\nofill{}\arg{}LHS\lisp{} -> \arg{}RHS\lisp{};\par}\rm{}





\lisp{}{\nofill{}IF \arg{}LHS\lisp{} THEN \arg{}RHS\lisp{};\par}\rm{}



The \lisp{}If\rm{} and \lisp{}Then\rm{} tokens are recognized in several combinations of upper and lower case letters.  The syntax for LHSs and RHSs is given below.  In addition, a rule can have no conditions (meaning always perform the actions) as follows:



\lisp{}{\nofill{}-> \arg{}RHS\lisp{};\par}\rm{}

  



\lisp{}{\nofill{}if T then \arg{}RHS\lisp{};\par}\rm{}



Rules can be preceded by a meta-description in braces as in:



\lisp{}{\nofill{}{\char'173}\arg{}MD\lisp{}{\char'175} \arg{}LHS\lisp{} -> \arg{}RHS\lisp{};\par}\rm{}





\lisp{}{\nofill{}{\char'173}\arg{}MD\lisp{}{\char'175} If \arg{}LHS\lisp{} Then \arg{}RHS\lisp{};\par}\rm{}





\lisp{}{\nofill{}{\char'173}\arg{}MD\lisp{}{\char'175} \arg{}RHS\lisp{};\par}\rm{}



Examples of meta-information include rule-specific control information, rule descriptions, audit instructions, and debugging instructions.  For example, the syntax for one-shot rules shown on page X.XX:



\lisp{}{\nofill{}{\char'173}1{\char'175} IF \arg{}condition\sub{1}\lisp{} \arg{}condition\sub{2}\lisp{} THEN \arg{}action\sub{1}\lisp{};\par}\rm{}



is an example of a meta-description.  Another example is the use of meta-assignment statements for describing audit trails and rules.  These statements are discussed on page X.XX.

\sl{}LHS Syntax:\rm{}  The clauses on the LHS of a rule are evaluated in order from left to right to determine whether the LHS is satisfied.  If they are all satisfied, then the rule is satisfied.  For example:



\lisp{}{\nofill{}A B C+D (Prime D) -> \arg{}RHS\lisp{};\par}\rm{}



In this rule, there are four clauses on the LHS.  If the values of some of the clauses are \lisp{}NIL\rm{} during evaluation, the remaining clauses are not evaluated.  For example,  if \lisp{}A\rm{} is non-\lisp{}NIL\rm{} but \lisp{}B\rm{} is \lisp{}NIL\rm{}, then the LHS is not satisfied and \lisp{}C+D\rm{} will not be evaluated.

\sl{}RHS Syntax:\rm{}  The RHS of a rule consists of actions to be performed if the LHS of the rule is satisfied.  These actions are evaluated in order from left to right.  Actions can be the invocation of RuleSets, the sending of Loops messages, Interlisp function calls, variables, or special termination actions.

RuleSets always return a value.  The value returned by a RuleSet is the value of the last rule that was executed.  Rules can have multiple actions on the right hand side.  Unless there is a \lisp{}Stop\rm{} statement or transfer call as described later, the value of a rule is the value of the last action.  When a rule has no actions on its RHS, it returns \lisp{}NIL\rm{} as its value.

\sl{}Comments:\rm{}  Comments can be inserted between rules in the RuleSet.  They are enclosed in parentheses with an asterisk for the first character as follows:  



\lisp{}{\nofill{}(* This is a comment)\par}\rm{}











\vskip10pt

\bf{}\noindent\save0\hbox{11.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Kinds of Variables

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 3306 \count0)}}\penalty 2000
\mark{Kinds of Variables}
\penalty 2000
\vskip10pt
\penalty 2000
Loops distinguishes the following kinds of variables:

\sl{}RuleSet arguments:\rm{}  All RuleSets have the variable \lisp{}self\rm{}{\send1{(RULESLANGUAGE.IM;4 3445 \count0)}} as their workspace.  References to \lisp{}self\rm{} can often be elided in the RuleSet syntax.  For example, the expression \lisp{}self.Print\rm{} means to send a \lisp{}Print\rm{} message to \lisp{}self\rm{}.  This expression can be shortened to \lisp{}.Print\rm{} .  Other arguments can be defined for RuleSets.  These are declared in an \lisp{}Args:\rm{} declaration.

\sl{}Instance variables:\rm{}  All RuleSets use a Loops object for their workSpace.  In the LHS and RHS of a rule, the first interpretation tried for an undeclared literal is as an instance variable in the work space.  Instance variables can be indicated unambiguously by preceding them with a colon, (e.g., \lisp{}:\arg{}varName\lisp{}\rm{} or \lisp{}\arg{}obj\lisp{}:\arg{}varName\lisp{}\rm{}).

\sl{}Class variables:\rm{}  Literals can be used to refer to class variables of Loops objects.  These variables must be preceded by a double colon in the rule language, (e.g., \lisp{}::\arg{}classVarName\lisp{}\rm{} or \lisp{}\arg{}obj\lisp{}::\arg{}classVarName\lisp{}\rm{}). 

\sl{}Temporary variables:\rm{}  Literals can also be used to refer to temporary variables allocated for a specific invocation of a RuleSet.  These variables are initialized to \lisp{}NIL\rm{} when a RuleSet is invoked.  Temporary variables are declared in the \lisp{}Temporary Vars\rm{} declaration in a RuleSet. 

\sl{}Task variables:\rm{}  [not implemented yet.]  Task variables are used for saving information state information related to particular invocations of RuleSets.  Unlike temporary variables which are reset to \lisp{}NIL\rm{} at the beginning of RuleSet execution, Task variables are associated with Task objects and keep their values indefinitely.  Task variables are used to hold information about a computational process, such as indices for generator Tasks.  Task variables are declared indirectly -- they are the instance variables of the class declared as the \sl{}Task Class\rm{}{\send1{(RULESLANGUAGE.IM;4 5281 \count0)}} of the RuleSet. 

\sl{}Audit record variables:\rm{}  Literals can also be used to refer to instance variables of audit records created by rules.  These literals are used only in \sl{}meta-assignment\rm{} statements in the MD part of a rule.  They are used to describe the information saved in audit records, which can be created as a side-effect of rule execution.  These variables are ignored if a RuleSet is not compiled in \sl{}audit\rm{} mode.  Undeclared variables appearing on the left side of assignment statements in the MD part of a rule are treated as audit record variables by default.  These variables are declared indirectly -- they are the instance variables of the class declared as the \sl{}Audit Class\rm{}{\send1{(RULESLANGUAGE.IM;4 6004 \count0)}} of the RuleSet. 

\sl{}Rule variables:\rm{}  [Not implemented yet.]  Literals can also be used to hold descriptions of the rules themselves.  These variables are used only in \sl{}meta-assignment\rm{} statements in the MD part of a rule.  They describe information to be saved in the rule objects, which are created as a side-effect of RuleSet compilation.  Rule variables are declared indirectly -- they are the instance variables in the \sl{}Rule Class\rm{}{\send1{(RULESLANGUAGE.IM;4 6467 \count0)}} declaration. 

\sl{}Interlisp variables:\rm{}  Literals can also be used to refer to Interlisp variables during the invocation of a RuleSet.  These variables can be global to the Interlisp environment, or are bound in some calling function.  Interlisp variables can be used when procedure-oriented and rule-oriented programs are intermixed.  Interlisp variables must be preceded by a backSlash in the syntax of the rule language (e.g., \lisp{}{\char'134}\arg{}lispVarName\lisp{}\rm{}). 

\sl{}Reserved Words:\rm{}   The following literals are treated as \sl{}read-only\rm{} variables with special interpretations:



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7071 \count0)}}\formatdef{462pt}{\lisp{}self\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent The current work space.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7124 \count0)}}\formatdef{462pt}{\lisp{}rs\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent The current RuleSet.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7176 \count0)}}\formatdef{462pt}{\lisp{}task\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent The Task representing the current invocation of this RuleSet.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7271 \count0)}}\formatdef{462pt}{\lisp{}caller\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent The RuleSet that invoked the current RuleSet, or \lisp{}NIL\rm{} if invoked otherwise.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7391 \count0)}}\formatdef{462pt}{\lisp{}ruleApplied\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Set to \lisp{}T\rm{} if some rule was applied in this cycle.  (For use only in while-conditions).


\parshape 1    0pt  462pt {}



The following reserved words are intended mainly for use in creating audit trails:



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7606 \count0)}}\formatdef{462pt}{\lisp{}ruleObject\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Variable bound to the object representing the rule itself.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7702 \count0)}}\formatdef{462pt}{\lisp{}ruleNumber\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Variable bound to the sequence number of the rule in a RuleSet.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7802 \count0)}}\formatdef{462pt}{\lisp{}ruleLabel\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Variable bound to the label of a rule or \lisp{}NIL\rm{}.



\parshape 1    0pt  462pt {}







\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 7966 \count0)}}\formatdef{462pt}{\lisp{}reasons\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Variable bound a list of audit records supporting the instance variables mentioned on the LHS of the rule.  (Computed at run time.)


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 8136 \count0)}}\formatdef{462pt}{\lisp{}auditObject\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Variable bound to the object to which the reason record will be attached.  (Computed at run time.)


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 8274 \count0)}}\formatdef{462pt}{\lisp{}auditVarName\rm{}}{Variable}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Variable bound to the name of the variable on which the reason will be attached as a property.


\parshape 1    0pt  462pt {}


\sl{}Other Literals:\rm{}  As described later, literals can also refer to Interlisp functions, Loops objects, and message selectors.  They can also be used in strings and quoted constants.

The determination of the meaning of a literal is done at compile time using the declarations and syntax of RuleSets.  The characters used in literals are limited to alphabetic characters and numbers.  The first character of a literal must be alphabetic.

The syntax of literals also includes a compact notation for sending unary messages and for accessing instance variables of Loops objects.  This notation uses \sl{}compound literals\rm{}.{\send1{(RULESLANGUAGE.IM;4 9021 \count0)}}   A compound literal is a literal composed of multiple parts separated by a periods, colons, and commas.











\vskip10pt

\bf{}\noindent\save0\hbox{11.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Rule Forms

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 9215 \count0)}}\penalty 2000
\mark{Rule Forms}
\penalty 2000
\vskip10pt
\penalty 2000
\sl{}Quoted Constants:\rm{}  The quote sign is used to indicate constant literals:



\lisp{}{\nofill{}a b=3 c='open d=f  e='(This is a quoted expression) -> ...\par}\rm{}



In this example, the LHS is satisfied if \lisp{}a\rm{} is non-\lisp{}NIL\rm{}, and the value of \lisp{}b\rm{} is 3, and the value of \lisp{}c\rm{} is exactly the atom \lisp{}open\rm{}, the value of \lisp{}d\rm{} is the same as the value of \lisp{}f\rm{}, and the value of \lisp{}e\rm{} is the list \lisp{}(This is a quoted expression)\rm{}. 

\sl{}Strings:\rm{}  The double quote sign is used to indicate string constants:



\lisp{}{\nofill{}IF a b=3 c='open d=f  e=="This is a string"  
THEN (WRITE "Begin configuration task") ... ;\par}\rm{}



In this example, the LHS is satisfied if \lisp{}a\rm{} is non-\lisp{}NIL\rm{}, and the value of \lisp{}b\rm{} is 3, and the value of \lisp{}c\rm{} is exactly the atom \lisp{}open\rm{}, the value of \lisp{}d\rm{} is the same as the value of \lisp{}f\rm{}, and the value of \lisp{}e\rm{} equal to the string \lisp{}"This is a string"\rm{}. 

\sl{}Interlisp Constants:\rm{}  The literals \lisp{}T\rm{} and \lisp{}NIL\rm{} are interpreted as the Interlisp constants of the same name.



\lisp{}{\nofill{}a (Foo x NIL b) -> x{\char'137}T ...;\par}\rm{}



In this example, the function \lisp{}Foo\rm{} is called with the arguments \lisp{}x\rm{}, \lisp{}NIL\rm{}, and \lisp{}b\rm{}.  Then the variable \lisp{}x\rm{} is set to \lisp{}T\rm{}. 









\vskip10pt

\bf{}\noindent\save0\hbox{11.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Infix Operators and Brackets

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 10575 \count0)}}\penalty 2000
\mark{Infix Operators and Brackets}
\penalty 2000
\vskip10pt
\penalty 2000
To enhance the readability of rules, a few infix operators are provided.  The following are infix binary operators in the rule syntax:




\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 10763 \count0)}}\formatdef{462pt}{\lisp{}+\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Addition.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 10827 \count0)}}\formatdef{462pt}{\lisp{}++\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Addition modulo 4.


\parshape 1    0
pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 10899 \count0)}}\formatdef{462pt}{\lisp{}-\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Subtraction.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 10970 \count0)}}\formatdef{462pt}{\lisp{}-\rm{}\lisp{}-\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Subtraction modulo 4.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11045 \count0)}}\formatdef{462pt}{\lisp{}*\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Multiplication.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11114 \count0)}}\formatdef{462pt}{\lisp{}{\char'57}\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Division.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11177 \count0)}}\formatdef{462pt}{\lisp{}>\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Greater than.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11244 \count0)}}\formatdef{462pt}{\lisp{}<\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Less than.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11309 \count0)}}\formatdef{462pt}{\lisp{}>=\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Greater than or equal.


\parshape 1    0
pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11386 \count0)}}\formatdef{462pt}{\lisp{}<=\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Less than or equal.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11459 \count0)}}\formatdef{462pt}{\lisp{}=\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}EQ\rm{} -- simple form of equals.  Works for atoms, objects, and small integers.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11594 \count0)}}\formatdef{462pt}{\lisp{}{\char'176}=\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}NEQ\rm{}.  (Not \lisp{}EQ\rm{}.)


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11674 \count0)}}\formatdef{462pt}{\lisp{}==\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent \lisp{}EQUAL\rm{} -- long form of equals.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11763 \count0)}}\formatdef{462pt}{\lisp{}<<\rm{}}{Rule Infix Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Member of a list.  (\lisp{}FMEMB\rm{})


\parshape 1    0pt  462pt {}


In addition, the rule syntax provides two unary operators as follows:



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11920 \count0)}}\formatdef{462pt}{\lisp{}-\rm{}}{Rule Unary Operator}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Minus.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 11980 \count0)}}\formatdef{462pt}{\lisp{}{\char'176}\rm{}}{Rule Unary Operator}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Not.


\parshape 1    0
pt  462pt {}


The precedence of operators in rule syntax follows the usual convention of programming languages.  For example



\lisp{}{\nofill{}1+5*3 = 16\par}\rm{}



and



\lisp{}{\nofill{}[3 < 2 + 4] = T\par}\rm{}



Brackets can be used to control the order of evaluation:



\lisp{}{\nofill{}[1+5]*3 = 18\par}\rm{}



\sl{}Ambiguity of the minus sign:\rm{}  Whenever there is an ambiguity about the interpretation of a minus sign as a unary or binary operator, the rule syntax interprets it as a binary minus.  For example



\lisp{}{\nofill{}a-b c d  -e  [-f]  (g -h)  ({\char'137} {\char'44}Foo Move -j) -> ...\par}\rm{}



In this example, the first and second minus signs are both treated as binary subtraction statements.  That is, the first three clauses are (1) \lisp{}a-b\rm{}, (2) \lisp{}c\rm{} and (3) \lisp{}d-e\rm{}.  Because the rule syntax allows arbitary spacing between symbols and there is no syntax to separate clauses on the LHS of a rule, the interpretation of {\lquotes}\lisp{}d  -e\rm{}{\rquotes} is as a single clause (with the subtraction) instead of two clauses.  To force the interpretation as a unary minus operator, one must use brackets as illustrated in the next clause.  In this clause, the minus sign in the clause \lisp{}[-f]\rm{} is treated as a unary minus because of the brackets.  The minus sign in the function call \lisp{}(g -h)\rm{} is treated as unary because there is no preceding argument. Similarly, the \lisp{}-j\rm{} in the message expression is treated as unary because there is no preceding argument.









\vskip10pt

\bf{}\noindent\save0\hbox{11.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Interlisp Functions and Message Sending

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 13531 \count0)}}\penalty 2000
\mark{Interlisp Functions and Message Sending}
\penalty 2000
\vskip10pt
\penalty 2000
Calls to Interlisp functions are parenthesized with the function name as the first literal after the left parenthesis.  Each expression after the function name is treated as an argument to the function.  For example:   



\lisp{}{\nofill{}a (Prime b) [a -b] -> c (Display b c+4 (Cursor x y) 2) ;\par}\rm{}



In this example, \lisp{}Prime\rm{}, \lisp{}Display\rm{}, and \lisp{}Cursor\rm{} are interpreted as the names of Interlisp functions.  Since the expression \lisp{}[a -b]\rm{} is surrounded by brackets instead of parentheses, it is recognized as meaning \lisp{}a\rm{} minus \lisp{}b\rm{} as opposed to a call to the function \lisp{}a\rm{} with the argument minus \lisp{}b\rm{}.  In the example above, the call to the Interlisp function \lisp{}Display\rm{} has four arguments: \lisp{}b\rm{}, \lisp{}c+4\rm{}, the value of the function call \lisp{}(Cursor x y)\rm{}, and \lisp{}2\rm{}.

The use of Interlisp functions is usually outside the spirit of the rule language.  However, it enables the use of Boolean expressions on the LHS beyond simple conjunctions.  For example:



\lisp{}{\nofill{}a (OR (NOT b) x y) z -> ... ;\par}\rm{}




\sl{}Loops Objects and Message Sending:\rm{}  Loops classes and other named objects can be referenced by using the dollar notation.  The sending of Loops messages is indicated by using a left arrow.  For example:



\lisp{}{\nofill{}IF cell{\char'137}({\char'137} {\char'44}LowCell Occupied? 'Heavy)  
THEN ({\char'137} cell Move 3 'North);\par}\rm{}



In the LHS, an \lisp{}Occupied?\rm{} message is sent to the object named \lisp{}LowCell\rm{}.  In the message expression on the RHS, there is no dollar sign preceding \lisp{}cell\rm{}.  Hence, the message is sent to the object that is the value of the variable \lisp{}cell\rm{}.

For unary messages (i.e., messages with only the selector specified and the implicit argument \lisp{}self\rm{}), a more compact notation is available as described selow.   


\sl{}Unary Message Sending:\rm{}  When a period is used as the separator in a compound literal, it indicates that a unary message is to be sent to an object.  (We will alternatively refer to a period as a \sl{}dot\rm{}.){\send1{(RULESLANGUAGE.IM;4 15514 \count0)}}  For example:



\lisp{}{\nofill{}tile.Type='BlueGreenCross command.Type='Slide4 -> ... ;\par}\rm{}



In this example, the object to receive the unary message \lisp{}Type\rm{} is referenced indirectly through the \lisp{}tile\rm{} instance variable in the work space.  The left literal is the variable \lisp{}tile\rm{} and its value must be a Loops object at execution time.  The right literal must be a method selector for that object.

The dot notation can be combined with the dollar notation to send unary messages to named Loops objects.  For example,



\lisp{}{\nofill{}{\char'44}Tile.Type='BlueGreenCross ...\par}\rm{}



In this example, a unary \lisp{}Type\rm{} message is sent to the Loops object whose name is \lisp{}Tile\rm{}.

The dot notation can also be used to send a message to the work space of the RuleSet, that is, \lisp{}self\rm{}.  For example, the rule

\lisp{}IF scale>7 THEN .DisplayLarge;\rm{}

would cause a \lisp{}DisplayLarge\rm{} message to be sent to \lisp{}self\rm{}.  This is an abbreviation for 



\lisp{}{\nofill{}IF scale>7 THEN self.DisplayLarge;\par}\rm{}











\vskip10pt

\bf{}\noindent\save0\hbox{11.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Variables and Properties

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 16635 \count0)}}\penalty 2000
\mark{Variables and Properties}
\penalty 2000
\vskip10pt
\penalty 2000
When a single colon is used in a literal, it indicates access to an instance variable of an object.  For example: 



\lisp{}{\nofill{}tile:type='BlueGreenCross command:type=Slide4 -> ... ;\par}\rm{}



In this example, access to the Loops object is indirect in that it is referenced through an instance variable of the work space.  The left literal is the variable \lisp{}tile\rm{}, and its value must be a Loops object when the rule is executed.  The right literal \lisp{}type\rm{} must be the name of an instance variable of that object.  The compound literal \lisp{}tile:type\rm{} refers to the value of the \lisp{}type\rm{} instance variable of the object in the instance variable \lisp{}tile\rm{}.

The colon notation can be combined with the dollar notation to access a variable in a named Loops object.  For example,



\lisp{}{\nofill{}{\char'44}TopTile:type='BlueGreenCross ...\par}\rm{}



refers to the \lisp{}type\rm{} variable of the object whose Loops name is \lisp{}TopTile\rm{}.  

A double colon notation is provided for accessing class variables.  For example



\lisp{}{\nofill{}truck::MaxGas<45 ::ValueAdded>600 -> ... ;\par}\rm{}



In this example, \lisp{}MaxGas\rm{} is a class variable of the object bound to \lisp{}truck\rm{}.  \lisp{}ValueAdded\rm{} is a class variable of \lisp{}self\rm{}.

A colon-comma notation is provided for accessing property values of class and instance variables.  For example



\lisp{}{\nofill{}wire:,capacitance>5  wire:voltage:,support='simulation -> ... \par}\rm{}



In the first clause, \lisp{}wire\rm{} is an instance variable of the work space and \lisp{}capacitance\rm{} is a property of that variable.  The interpretation of the second clause is left to right as usual: (1) the object that is the value of the variable \lisp{}wire\rm{} is retrieved, and (2) the \lisp{}support\rm{} property of the \lisp{}voltage\rm{} variable of that object is retrieved.  For properties of class variables



\lisp{}{\nofill{}::Wire:,capacitance>5  node::Voltage:,support='simulation -> ... \par}\rm{}



In the first clause, \lisp{}wire\rm{} is a class variable of the work space and \lisp{}capacitance\rm{} is a property of that variable.  In the second clause, \lisp{}node\rm{} is an instance variable bound to some object.  \lisp{}Voltage\rm{} is a class variable of that object, and \lisp{}Support\rm{} is a property of that class variable.



The property notation is illegal for ruleVars and lispVars since those variables cannot have properties.










\vskip10pt

\bf{}\noindent\save0\hbox{11.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Perspectives

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 19293 \count0)}}\penalty 2000
\mark{Perspectives}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 19315 \count0)}}

* * * Not implemented yet in the rule language * * *

In many cases it is useful to organize information in terms of multiple points of view.  For example, information about a man might be organized in terms of his role as a \sl{}father\rm{}, as an \sl{}employee\rm{}, and as a \sl{}traveler\rm{}.  Each point of view, called a \sl{}perspective\rm{}, contains information for a different purpose.  The perspectives are related to each other in the sense that they collectively provide information about the same object.  As described in the Loops manual, Loops supports this organizational metaphor by providing special mixin classes called \lisp{}perspectives\rm{} and \lisp{}nodes\rm{}.  

Loops perspectives can be accessed in the rule language by using a comma notation.  In the following rule, the variable \lisp{}washingMachine\rm{} is bound to an object with three perspectives: \lisp{}commodity\rm{}, \lisp{}electrical\rm{}, and \lisp{}cleaning\rm{}.  The rule accesses the \lisp{}voltage\rm{} variable of the object that is the \lisp{}electrical\rm{} perspective. 



\lisp{}{\nofill{}IF washingMachine,electrical:voltage<100 THEN ....\par}\rm{}



In this syntax, the term before the comma names a variable, and the term after the comma is the name of the perspective. 









\vskip10pt

\bf{}\noindent\save0\hbox{11.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Computing Selectors and Variable Names

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 20654 \count0)}}\penalty 2000
\mark{Computing Selectors and Variable Names}
\penalty 2000
\vskip10pt
\penalty 2000
The short notations for instance variables, properties, perspectives, and unary messages all show the selector, variable, and perspective names \sl{}as they actually appear\rm{} in the object.



\lisp{}{\nofill{}\arg{}object\lisp{}.\arg{}selector\lisp{}
\arg{}object\lisp{}:\arg{}ivName\lisp{}
\arg{}object\lisp{}::\arg{}cvName\lisp{}
\arg{}object\lisp{}:\arg{}varname\lisp{}:,\arg{}propName\lisp{}
\arg{}object\lisp{},\arg{}perspName\lisp{}

({\char'137} \arg{}object\lisp{} \arg{}selector\lisp{} \arg{}arg\sub{1}\lisp{} \arg{}arg\sub{2}\lisp{})\par}\rm{}



For example, 



\lisp{}{\nofill{}apple:flavor\par}\rm{}



refers to the \lisp{}flavor\rm{} instance variable of the object bound to the variable \lisp{}apple\rm{}.  In Interlisp terminology, this implies implicit quoting of the name of the instance variable (\lisp{}flavor\rm{}).  

In some applications it is desired to be able to compute the names, For this, the Loops rule language provides analogous notations with an added exclamation sign.  After the exclamation sign, the interpretation of the variable being evaluated starts over again.  For example



\lisp{}{\nofill{}apple:!{\char'134}x\par}\rm{}



refers to the same thing as \lisp{}apple:flavor\rm{} if the Interlisp variable \lisp{}x\rm{} is bound to \lisp{}flavor\rm{}.  The fact that \lisp{}x\rm{} is a Lisp variable is indicated by the backSlash.  If \lisp{}x\rm{} is an instance variable of \lisp{}self\rm{} or a temporary variable, we could use the notation: 



\lisp{}{\nofill{}apple:!x\par}\rm{}



If \lisp{}x\rm{} is a class variable of \lisp{}self\rm{}, we could use the notation: 



\lisp{}{\nofill{}apple:!::x\par}\rm{}



All combinations are possible, including: 



\lisp{}{\nofill{}\arg{}object\lisp{}.!\arg{}selector\lisp{}
\arg{}object\lisp{}.!{\char'134}\arg{}selector\lisp{}
\arg{}object\lisp{}.!::\arg{}selector\lisp{}
\arg{}object\lisp{}:!\arg{}ivName\lisp{}
\arg{}object\lisp{}::!\arg{}cvName\lisp{}
\arg{}object\lisp{}:!\arg{}varname\lisp{}:,\arg{}propName\lisp{}
\arg{}object\lisp{},!\arg{}perspName\lisp{}

({\char'137}! \arg{}object\lisp{} \arg{}selector\lisp{} \arg{}arg\sub{1}\lisp{} \arg{}arg\sub{2}\lisp{})\par}\rm{}











\vskip10pt

\bf{}\noindent\save0\hbox{11.9}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Recursive Compound Literals

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 22519 \count0)}}\penalty 2000
\mark{Recursive Compound Literals}
\penalty 2000
\vskip10pt
\penalty 2000
Multiple colons or periods can be used in a literal,  For example:



\lisp{}{\nofill{}a:b:c\par}\rm{}



means to (1) get the object that is the value of \lisp{}a\rm{}, (2) get the object that is the value of the \lisp{}b\rm{} instance variable of \lisp{}a\rm{}, and finally (3) get the value of the \lisp{}c\rm{} instance variable of that object.  

Similarly, the notation



\lisp{}{\nofill{}a.b:c\par}\rm{}



means to get the \lisp{}c\rm{} variable of the object returned after sending a \lisp{}b\rm{} message to the object that is the value of the variable \lisp{}a\rm{}.  Again, the operations are carried out left to right: (1) the object that is the value of the variable \lisp{}a\rm{} is retrieved, (2) it is sent a \lisp{}b\rm{} message which must return an object, and then (3) the value of the \lisp{}c\rm{} variable of that object is retrieved.

Compound literal notation can be nested arbitrarily deeply.










\vskip10pt

\bf{}\noindent\save0\hbox{11.10}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Assignment Statements

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 23471 \count0)}}\penalty 2000
\mark{Assignment Statements}
\penalty 2000
\vskip10pt
\penalty 2000
An assignment statement using a left arrow can be used for setting all kinds of variables.  For example,



\lisp{}{\nofill{}x{\char'137}a;\par}\rm{}



sets the value of the variable \lisp{}x\rm{} to the value of \lisp{}a\rm{}.  The same notation works if \lisp{}x\rm{} is a task variable, rule variable, class variable, temporary variable, or work space variable.  The right side of an assignment statement can be an expression as in:



\lisp{}{\nofill{}x{\char'137}a*b + 17*(LOG d);\par}\rm{}



The assignment statement can also be used with the colon notation to set values of instance variables of objects.  For example:



\lisp{}{\nofill{}y:b{\char'137}0 ;\par}\rm{}



In this example, first the object that is the value of \lisp{}y\rm{}is computed, then the value of its instance variable \lisp{}b\rm{} is set to \lisp{}0\rm{}.

\sl{}Properties and perspectives:\rm{}  Assignment statements can also be used to set property values as in:   



\lisp{}{\nofill{}box:x:,origin{\char'137}47   fact:,reason{\char'137}currentSupport;\par}\rm{}



or variables of perspectives as in:.   



\lisp{}{\nofill{}washingMachine,electrical:voltage{\char'137}110;\par}\rm{}



\sl{}Nesting:\rm{}  Assignment statements can be nested as in



\lisp{}{\nofill{}a{\char'137}b{\char'137}c:d{\char'137}3;\par}\rm{}



This statement sets the values of \lisp{}a\rm{}, \lisp{}b\rm{}, and the \lisp{}d\rm{} instance variable of \lisp{}c\rm{} to \lisp{}3\rm{}.  The value of an assignment statement itself is the new assigned value.   









\vskip10pt

\bf{}\noindent\save0\hbox{11.11}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Meta-Assignment Statements

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 24845 \count0)}}\penalty 2000
\mark{Meta-Assignment Statements}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 24868 \count0)}}
Meta-assignment statements are assignment statements used for specifying rule descriptions and audit trails.  These statements appear in the MD part of rules.

\sl{}Audit Trails:\rm{}  The default interpretation of meta-assignment statements for undeclared variables is as audit trail specifications.  Each meta-assignment statement specifies information to be saved in audit records when a rule is applied.  In the following example from figure X.X, the audit record must have variables named \lisp{}basis\rm{} and \lisp{}cf\rm{}:




\lisp{}{\nofill{}{\char'173}(basis{\char'137}'Fact cf{\char'137}1){\char'175}
IF buyer:familySize>2  machine:capacity<20
THEN suitability{\char'137}'Poor;\par}\rm{}



In this example, the RHS of the rule assigns the value of the work space instance variable \lisp{}suitability\rm{} to \lisp{}'Poor\rm{} if the conditions of the rule are satisfied.  In addition, if the RuleSet was compiled in \sl{}audit\rm{} mode, then during RuleSet execution an audit record is created as a side-effect of the assignment.  The audit record is attached to the \lisp{}reason\rm{} property of the suitability variable.  It has instance variables \lisp{}basis\rm{} and \lisp{}cf\rm{}.  

In general, an audit description consists of a sequence of meta-assignment statements.  The assignment variable on the left must be an instance variable of the audit record.  The class of the audit record is declared in the \sl{}Audit Class\rm{}{\send1{(RULESLANGUAGE.IM;4 26244 \count0)}} declaration of the RuleSet.  The expression on the right is in terms of the variables accessible by the RuleSet.  If the conditions of a rule are satisfied, an audit record is instantiated.  Then the meta-assignment statements are evaluated in the execution context of the RuleSet and their values are put into the audit record.  A separate audit record is created for each of the object variables that are set by the rule.  






\sl{}Rule Descriptions:\rm{}  Meta-assignment statements can also be used to set variables in the objects that represent individual rules.  This interpretation of meta-assignment statements is indicated when the assignment variable of the meta-assignment statement has been declared to be a rule variable.  For example, if the variable \lisp{}cf\rm{} in the previous example was declared to be a rule variable, then the meta-assignment statement would set the \lisp{}cf\rm{} instance variable of the rule object to \lisp{}.5\rm{} at compilation time, instead of saving a \lisp{}cf\rm{} in every audit record for every rule application at execution time.  The value on the right hand side of the meta-assignment statement for a rule variable must be known at compile time.  









\vskip10pt

\bf{}\noindent\save0\hbox{11.12}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Push and Pop Statements

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 27850 \count0)}}\penalty 2000
\mark{Push and Pop Statements}
\penalty 2000
\vskip10pt
\penalty 2000
A compact notation is provided for pushing and popping values from lists.  To push a new value onto a list, the notation \lisp{}{\char'137}+\rm{}{\send1{(RULESLANGUAGE.IM;4 28014 \count0)}} is used:



\lisp{}{\nofill{}myList{\char'137}+newItem;\par}\rm{}





\lisp{}{\nofill{}focus:goals{\char'137}+newGoal;\par}\rm{}



To pop an item from a list, the \lisp{}{\char'137}-\rm{}{\send1{(RULESLANGUAGE.IM;4 28161 \count0)}} notation is used:



\lisp{}{\nofill{}item{\char'137}-myList;\par}\rm{}





\lisp{}{\nofill{}nextGoal{\char'137}-focus:goals;\par}\rm{}



As with the assignment operator, the push and pop notation works for all kinds of variables and properties.  They can be used in conjunction with infix operator \lisp{}<<\rm{} for membership testing.  









\vskip10pt

\bf{}\noindent\save0\hbox{11.13}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Invoking RuleSets

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 28545 \count0)}}\penalty 2000
\mark{Invoking RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
One of the ways to cause RuleSets to be executed is to invoke them from rules.  This is used on the LHS of rules to express predicates in terms of RuleSets, and on the RHS of rules to express actions in terms of RuleSets.  A short double-dot syntax for this is provided that invokes a RuleSet on a work space:



\lisp{}{\nofill{}Rs1..ws1\par}\rm{}



In this example, the RuleSet bound to the variable \lisp{}Rs1\rm{} is invoked with the value of the variable \lisp{}ws1\rm{} as its work space.  The value of the invocation expression is the value returned by the RuleSet.  The double-dot syntax can be combined with the dollar notation to invoke a RuleSet by its Loops name, as in



\lisp{}{\nofill{}{\char'44}MyRules..ws1\par}\rm{}



which invokes the RuleSet object that has the Loops name \lisp{}MyRules\rm{}.

This form of RuleSet invocation is like subroutine calling, in that it creates an implicit stack of arguments and return addresses.  This feature can be used as a mechanism for \sl{}meta-control\rm{} of RuleSets as in:



\lisp{}{\nofill{}IF breaker:status='Open 
THEN source{\char'137}{\char'44}OverLoadRules..washingMachine;

IF source='NotFound
THEN {\char'44}ShortCircuitRules..washingMachine;\par}\rm{}



In this example, two {\lquotes}meta-rules{\rquotes} are used to control the invocation of specialized RuleSets for diagnosing overloads or short circuits.









\vskip10pt

\bf{}\noindent\save0\hbox{11.14}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Transfer Calls

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 29890 \count0)}}\penalty 2000
\mark{Transfer Calls}
\penalty 2000
\vskip10pt
\penalty 2000


An important optimization in many recursive programs is the elimination of tail recursion.  For example, suppose that the RuleSet A calls B, B calls C, and C calls A recursively.  If the first invocation of A must do some more work after returning from B, then it is useful to save the intermediate states of each of the procedures in frames on the calling stack.  For such programs, the space allocation for the stack must be enough to accommodate the maximum depth of the calls.  

There is a common and special case, however, in which it is unnecessary to save more than one frame on the stack.  In this case each RuleSet has no more work to do after invoking the other RuleSets, and the value of each RuleSet is the value returned by the RuleSet that it invokes.  RuleSet invocation in this case amounts to the evaluation of arguments followed by a direct transfer of control.  We call such invocations transfer calls.    

The Loops rule language extends the syntax for RuleSet invocation and message sending to provide this as follows:   



\lisp{}{\nofill{}RS..*ws\par}\rm{}



The RuleSet \lisp{}RS\rm{} is invoked on the work space \lisp{}ws\rm{}.  With transfer calls, RuleSet invocations can be arbitrarily deep without using proportional stack space.









\vskip10pt

\bf{}\noindent\save0\hbox{11.15}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Task Operations

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 31275 \count0)}}\penalty 2000
\mark{Task Operations}
\penalty 2000
\vskip10pt
\penalty 2000


Tasks in the Loops rule language represent the invocation of RuleSets.  They provide a mechanism for specifying and controlling processes in terms of tasks that can be created, started, suspended, and restarted.  They also provide a handle for specifying concurrent processing.

A Task records the work space of a RuleSet (\lisp{}ws\rm{}), the value returned (\lisp{}value\rm{}),  and two special variables called the \lisp{}status\rm{} and \lisp{}reason\rm{}.  A Task can also have RuleSet-specific instance variables called task variables for saving process information.    

\sl{}Creating Tasks:\rm{}  A Task is represented as a Loops object and can be created and associated with a work space as follows:



\lisp{}{\nofill{}Task6{\char'137}({\char'137} {\char'44}Task New \arg{}RuleSet\lisp{} \arg{}workSpace\lisp{})\par}\rm{}



The \arg{}workSpace\rm{} argument is optional.  Specialized versions of \lisp{}Task\rm{} will eventually be available, such as \lisp{}RemoteTask\rm{},  Information about a Task is stored in its instance variables, and can be accessed like other Loops variables:



\lisp{}{\nofill{}Task6:status
Task6:reason
Task6:ws
Task6:value\par}\rm{}





\sl{}Starting Tasks:\rm{}  The primary operations on Tasks are starting them and waiting for them to finish execution.  These operations have been designed to work when Loops is extended for concurrent processing.  The operations for starting tasks are as follows: 







\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 32700 \count0)}}\formatdef{462pt}{\lisp{}(Start1 \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 32741 \count0)}}\formatdef{462pt}{\lisp{}(StartAll \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 32786 \count0)}}\formatdef{462pt}{\lisp{}(StartAll \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Each of the start operations takes an argument \arg{}taskList\rm{} which is either a Task object, or a list of Task objects.  A Task cannot be started if it is already running, as indicated by its \lisp{}status\rm{} variable.  \lisp{}Start1\rm{} iterates through its \arg{}taskList\rm{} and starts the first Task that is not already running.  The value of \arg{}Start1\rm{} is the Task that was started.  \lisp{}StartAll\rm{} starts all of the tasks, and does not return control until all of the tasks have been started.  \lisp{}StartTogether\rm{} is like \lisp{}StartAll\rm{} except that none of the tasks are started until all of them are ready.  The synchronization aspect of \lisp{}StartTogether\rm{} is important for avoiding Task deadlock situations in programs that share Tasks as resources.  (It avoids the difficulties associated with partial allocation of Tasks when a complete set of Tasks is needed.)


\parshape 1    0pt  462pt {}


\sl{}Waiting for Tasks:\rm{}  The following operations are provided for waiting for Tasks:







\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 33774 \count0)}}\formatdef{462pt}{\lisp{}(Wait1 \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 33818 \count0)}}\formatdef{462pt}{\lisp{}(WaitAll \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}Wait1\rm{} iterates through its \arg{}taskList\rm{} and returns as its value the first Task that is not running.  \lisp{}WaitAll\rm{} returns when all of its Tasks have finished running  The value returned by the RuleSet that ran in a Task can be obtained from the Task object, as in:



\lisp{}{\nofill{}task6:value.\par}\rm{}





\parshape 1    0pt  462pt {}


\sl{}Running Tasks:\rm{}  In many cases, the specification of Task control can be simplified by using a \sl{}run\rm{} operation that combines the start and wait operations.  The run operations are as follows:







\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 34358 \count0)}}\formatdef{462pt}{\lisp{}(Run1 \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 34397 \count0)}}\formatdef{462pt}{\lisp{}(RunAll \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000








\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 34445 \count0)}}\formatdef{462pt}{\lisp{}(RunTogether \arg{}taskList\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}Run1\rm{} goes through its arguments left to right and selects the first Task that is not running.  It starts that Task and then waits for it to complete.  The value of \lisp{}Run1\rm{} is the Task that was executed.  \lisp{}RunAll\rm{} starts all of the Tasks running and then waits for them all to complete.  \lisp{}RunTogether\rm{} waits for all of the Tasks to become available, runs them all, and then waits for them all to complete.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{11.16}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Stop Statements

\rm{}\penalty 2000
{\send1{(RULESLANGUAGE.IM;4 34962 \count0)}}\penalty 2000
\mark{Stop Statements}
\penalty 2000
\vskip10pt
\penalty 2000
At invocation, the \lisp{}status\rm{} in the Task is set to \lisp{}Running\rm{}.  If a RuleSet ends normally, the \lisp{}status\rm{} in the Task is set to \lisp{}Done\rm{} and the \lisp{}reason\rm{} saved in the RuleStep is \lisp{}Success\rm{}.  Other terminations can be specified in a Stop statement as follows:  



\vskip 10pt
{\send1{(RULESLANGUAGE.IM;4 35391 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}(Stop \arg{}value\lisp{} \arg{}status\lisp{} \arg{}reason\lisp{})\lisp{}\rm{}}{RuleSet Statement}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent \arg{}value\rm{} is the value to be returned by the RuleSet, \arg{}status\rm{} characterizes the termination of the Task, and \arg{}reason\rm{} is a symbolic reason for the status.  Typical examples of the use of Stop are:



\lisp{}{\nofill{}(Stop \arg{}value\lisp{} 'Aborted \arg{}reason\lisp{})
(Stop \arg{}value\lisp{} 'Suspended \arg{}reason\lisp{})\par}\rm{}



where \lisp{}Aborted\rm{} means that the RuleSet has failed, and \lisp{}Suspended\rm{} means that the RuleSet has stopped but may be re-invoked.  Particular applications will probably develop standardized notations for status and reason.  Values for these can be Interlisp atoms or Loops objects.  The arguments \arg{}status\rm{} and \arg{}reason\rm{} are optional in a \lisp{}Stop\rm{} statement.


\parshape 1    0pt  462pt {}

















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{12}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}USING RULES IN LOOPS

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 72 \count0)}}\penalty 2000
\mark{USING RULES IN LOOPS}
\penalty 2000
\vskip10pt
\penalty 2000
The Loops rules language is supported by an integrated programming environment for creating, editing, compiling, and debugging RuleSets.  This section describes how to use that environment.




\vskip10pt

\bf{}\noindent\save0\hbox{12.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Creating RuleSets

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 331 \count0)}}\penalty 2000
\mark{Creating RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets are named Loops objects and are created by sending the class \lisp{}RuleSet\rm{}{\send1{(RULESUSE.IM;1 440 \count0)}} a \lisp{}New\rm{} message as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}RuleSet New)\par}\rm{}



After entering this form,  the user will be prompted for a Loops name as



\lisp{}{\nofill{}RuleSet name: \arg{}RuleSetName\lisp{}\par}\rm{}



Afterwards, the RuleSet can be referenced using Loops dollar sign notation as usual.  It is also possible to include the RuleSet name in the \lisp{}New\rm{} message as follows:



\lisp{}{\nofill{}({\char'137} {\char'44}RuleSet New NIL \arg{}RuleSetName\lisp{})\par}\rm{}













\vskip10pt

\bf{}\noindent\save0\hbox{12.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Editing RuleSets

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 1158 \count0)}}\penalty 2000
\mark{Editing RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
A RuleSet is created empty of rules.  The RuleSet editor is used to enter and modify rules.  The editor can be invoked with an \lisp{}EditRules\rm{}{\send1{(RULESUSE.IM;1 1330 \count0)}} message (or \lisp{}ER\rm{}{\send1{(RULESUSE.IM;1 1372 \count0)}} shorthand message) as follows:



\lisp{}{\nofill{}({\char'137} \arg{}RuleSet\lisp{} EditRules)
({\char'137} \arg{}RuleSet\lisp{} ER)\par}\rm{}



If a RuleSet is installed as a method of a class, it can be edited conveniently by selecting the \lisp{}EM\rm{} option from a browser containing the class.  Alternatively, the \lisp{}EM\rm{} function or \lisp{}EditMethod\rm{} message can be used:



\vskip 10pt
{\send1{(RULESUSE.IM;1 1834 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}ClassName\lisp{} EditMethod \arg{}selector\lisp{})\lisp{} \rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}







\vskip 10pt
{\send1{(RULESUSE.IM;1 1886 \count0)}}\formatdef{462pt}{\lisp{}(EM \arg{}ClassName selector\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}

Both approaches to editing retrieve the source of the RuleSet and put the user into the TTYIN editor, treating the rule source as text.



Initially, the source is a template for RuleSets as follows:




\vskip 10pt
\parshape 1   46pt  416pt {}

\lisp{}{\nofill{}RuleSet Name:         RuleSetName;
WorkSpace Class:      ClassName;
Control Structure:      doAll;   
While Condition: ;
Audit Class:         StandardAuditRecord;
Rule Class:            Rule;
Task Class:         ;
Meta Assignments:      ;
Temporary Vars:;
Lisp Vars:         ;
Debug Vars:      ;
Compiler Options:   ;       


   (* Rules for whatever.  Comment goes here.)\par}\rm{}




\parshape 1    0
pt  462pt {}\parshape 1   46pt  416pt {}Figure 22.   Initial template for a RuleSet.  The rules are entered after the comment at the bottom.  The declarations at the beginning are filled in as needed and superfluous declarations can be discarded.       


\parshape 1    0pt  462pt {}


The user can then edit this template to enter rules and set the declarations at the beginning.  In the current version of the rule editor, most of these declarations are left out.  If the user chooses the \lisp{}EditAllDecls\rm{} option in the RuleSet editor menu, the declarations and default values will be printed in full.

The template is only a guide.  Declarations that are not needed can be deleted.  For example, if there are no temporary variables for this RuleSet, the \lisp{}Temporary Vars\rm{} declaration can be deleted.  If the control structure is not one of the while control structures, then the \lisp{}While Condition\rm{} declaration can be deleted.  If the compiler option \lisp{}A\rm{} is not chosen, then the \lisp{}Audit Class\rm{} declaration can be deleted.

When the user leaves the editor, the RuleSet is compiled automatically into a LISP function.  



If a syntax error is detected during compilation, an error message is printed and the user is given another opportunity to edit the RuleSet. 










\vskip10pt

\bf{}\noindent\save0\hbox{12.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Copying RuleSets

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 4250 \count0)}}\penalty 2000
\mark{Copying RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
Sometimes it is convenient to create new RuleSets by editing a copy of an existing RuleSet.  For this purpose, the method \lisp{}CopyRules\rm{} is provided as follows:



\vskip 10pt
{\send1{(RULESUSE.IM;1 4565 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}oldRuleSet\lisp{} CopyRules \arg{}newRuleSetName\lisp{})\lisp{} \rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 


\parshape 1    0pt  462pt {}

This creates a new RuleSet by some of the information from the pespectives of the old RuleSet.   It also updates the source text of the new RuleSet to contain the new name.  










\vskip10pt

\bf{}\noindent\save0\hbox{12.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Saving RuleSets on LISP Files

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 4868 \count0)}}\penalty 2000
\mark{Saving RuleSets on LISP Files}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets can be saved on LISP files just like other Loops objects.  In addition, it is usually useful to save the LISP functions that result from RuleSet compilation.  In the current implementation, these functions have the same names as the RuleSets themselves.  To save RuleSets on a file, it is necessary to add two statements to the file commands for the file as follows:



\lisp{}{\nofill{}(FNS * MyRuleSetNames)
(INSTANCES * MyRuleSetNames)\par}\rm{}



where \lisp{}MyRuleSetNames\rm{} is a LISP variable whose value is a list of the names of the RuleSets to be saved.










\vskip10pt

\bf{}\noindent\save0\hbox{12.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Printing RuleSets

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 5535 \count0)}}\penalty 2000
\mark{Printing RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
To print a RuleSet without editing it, one can send a \lisp{}PPRules\rm{} or \lisp{}PPR\rm{} message as follows:



\vskip 10pt
{\send1{(RULESUSE.IM;1 5740 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}RuleSet\lisp{} PPRules)\lisp{} \rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000




\vskip 10pt
{\send1{(RULESUSE.IM;1 5836 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}RuleSet\lisp{} PPR)\lisp{} \rm{}}{Message}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}

A convenient way to make hardcopy listings of RuleSets is to use the function \lisp{}ListRuleSets\rm{}.{\send1{(RULESUSE.IM;1 5959 \count0)}}  The files will be printed on the \lisp{}DEFAULTPRINTINGHOST\rm{} as is standard in Interlisp-D.  \lisp{}ListRuleSets\rm{} can be given three kinds of arguments as follows:



\lisp{}{\nofill{}(ListRuleSets \arg{}RuleSetName\lisp{})
(ListRuleSets \arg{}ListOfRuleSetNames\lisp{})
(ListRuleSets \arg{}ClassName\lisp{})
(ListRuleSets \arg{}FileName\lisp{})\par}\rm{}



In the \arg{}ClassName\rm{} case, all of the RuleSets that have been installed as methods of the class will be printed.  In the last case, all of the RuleSets stored in the file will be printed.










\vskip10pt

\bf{}\noindent\save0\hbox{12.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Running RuleSets from Loops

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 6578 \count0)}}\penalty 2000
\mark{Running RuleSets from Loops}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets can be invoked from Loops using any of the usual protocols.

\sl{}Procedure-oriented Protocol:\rm{}  The way to invoke a RuleSet from Loops is to use the \lisp{}RunRS\rm{} function:







\vskip 10pt
{\send1{(RULESUSE.IM;1 6843 \count0)}}\formatdef{462pt}{\lisp{}(RunRS \arg{}RuleSet workSpace arg\sub{2} $\cdots$ arg\sub{N}\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent \arg{}workSpace\rm{} is the Loops object to be used as the work space.  This is {\lquotes}procedural{\rquotes} in the sense that the RuleSet is invoked by its name.  \arg{}RuleSet\rm{} can be either a RuleSet object or its name.


\parshape 1    0pt  462pt {}


\sl{}Object-oriented Protocol:\rm{}  When RuleSets are installed as methods in Loops classes, they can be invoked in the usual way by sending a message to an instance of the class.  For example, if \lisp{}WashingMachine\rm{} is a class with a RuleSet installed for its \lisp{}Simulate\rm{} method, the RuleSet is invoked as follows:



\lisp{}{\nofill{}({\char'137} washingMachineInstance Simulate)\par}\rm{}



\sl{}Data-oriented Protocol:\rm{}  When RuleSets are installed in active values, they are invoked by side-effect as a result of accessing the variable on which they are installed.









\vskip10pt

\bf{}\noindent\save0\hbox{12.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Installing RuleSets as Methods

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 7728 \count0)}}\penalty 2000
\mark{Installing RuleSets as Methods}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets can also be used as methods for classes.  This is done by installing automatically-generated invocation functions that invoke the RuleSets.  For example:



\lisp{}{\nofill{}[DEFCLASS WashingMachine
   (MetaClass Class doc (* comment) ...)
   ...
   (InstanceVariables (owner ...))
   (Methods
            (Simulate RunSimulateWMRules)
            (Check RunCheckWMRules
                        doc (* Rules to Check a washing machine.)) 
...]\par}\rm{}





When an instance of the class \lisp{}WashingMachine\rm{} receives a \lisp{}Simulate\rm{} message, the RuleSet \lisp{}SimulateWMRules\rm{} will be invoked with the instance as its work space.

To simplify the definition of RuleSets intended to be used as Methods, the function \lisp{}DefRSM\rm{} (for {\lquotes}Define Rule Set as a Method{\rquotes}) is provided:







\vskip 10pt
{\send1{(RULESUSE.IM;1 8565 \count0)}}\formatdef{462pt}{\lisp{}(DefRSM \arg{}ClassName Selector RuleSetName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent If the optional argument \arg{}RuleSetName\rm{} is given, \lisp{}DefRSM\rm{} installs that RuleSet as a method using the \arg{}ClassName\rm{} and \arg{}Selector\rm{}.  It does this by automatically generating an installation function as a method to invoke the RuleSet.  \lisp{}DefRSM\rm{} automatically documents the installation function and the method.

If the argument \arg{}RuleSetName\rm{} is \lisp{}NIL\rm{}, then \lisp{}DefRSM\rm{} creates the RuleSet object, puts the user into an Editor to enter the rules, compiles the rules into a LISP function, and installs the RuleSet as before.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{12.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Installing RuleSets in ActiveValues

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 9266 \count0)}}\penalty 2000
\mark{Installing RuleSets in ActiveValues}
\penalty 2000
\vskip10pt
\penalty 2000
RuleSets can also be used in data-oriented programming so that they are invoked when data is accessed.  To use a RuleSet as a \arg{}getFn\rm{}, the function \lisp{}RSGetFn\rm{}{\send1{(RULESUSE.IM;1 9450 \count0)}} is used with the property \lisp{}RSGet\rm{}{\send1{(RULESUSE.IM;1 9507 \count0)}} as follows:



\lisp{}{\nofill{}...
(InstanceVariables
     (\arg{}myVar\lisp{} {\char'43}(\arg{}myVal\lisp{} RSGetFn NIL) RSGet \arg{}RuleSetName\lisp{}))
...\par}\rm{}



\lisp{}RSGetFn\rm{} is a Loops system function that can be used in an active value to invoke a RuleSet in response to a Loops get operation (e.g., \lisp{}GetValue\rm{}) is performed.  It requires that the name of the RuleSet be found on the \lisp{}RSGet\rm{} property of the item.  \lisp{}RSGetFn\rm{} activates the RuleSet using the local state as the work space.  The value returned by the RuleSet is returned as the value of the get operation. 

To use a RuleSet as a \arg{}putFn\rm{}, the function \lisp{}RSPutFn\rm{}{\send1{(RULESUSE.IM;1 10132 \count0)}} is used with the property \lisp{}RSPut\rm{}{\send1{(RULESUSE.IM;1 10189 \count0)}} as follows:



\lisp{}{\nofill{}...
(InstanceVariables
     (\arg{}myVar\lisp{} {\char'43}(\arg{}myVal\lisp{} NIL RSPutFn) RSPut \arg{}RuleSetName\lisp{}))
...\par}\rm{}





\lisp{}RSPutFn\rm{} is a function that can be used in an active value to invoke a RuleSet in response to a Loops put operation (e.g., \lisp{}PutValue\rm{}).  It requires that the name of the RuleSet be found on the \lisp{}RSPut\rm{} property of the item.  \lisp{}RSGetFn\rm{} activates the RuleSet using the \arg{}newValue\rm{} from the put operation as the work space.  The value returned by the RuleSet is put into the local state of the active value. 










\vskip10pt

\bf{}\noindent\save0\hbox{12.9}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Tracing and Breaking RuleSets

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 10882 \count0)}}\penalty 2000
\mark{Tracing and Breaking RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
Loops provides breaking and tracing facilities to aid in debugging RuleSets.  These can be used in conjunction with the auditing facilities and the rule executive for debugging RuleSets.  figure X.X summarizes the compiler options for breaking and tracing:




\vskip 10pt
{\send1{(RULESUSE.IM;1 11196 \count0)}}
\parshape 1   46pt  416pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  129pt  333pt {}\save0\hbox{\lisp{}T\rm{}{\send1{(RULESUSE.IM;1 11273 \count0)}}}\noindent\ifdimen 1wd0>74pt{\hskip-83pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-83pt\box0\hskip0pt plus 1000pt minus 1000pt}}Trace if rule is satisfied.  Useful for creating a running display of executed rules.

\parshape 1   46pt  416pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  129
pt  333pt {}\save0\hbox{\lisp{}TT\rm{}{\send1{(RULESUSE.IM;1 11420 \count0)}}}\noindent\ifdimen 1wd0>74pt{\hskip-83pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-83pt\box0\hskip0pt plus 1000pt minus 1000pt}}Trace if rule is tested.

\parshape 1   46pt  416pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  129pt  333pt {}\save0\hbox{\lisp{}B\rm{}{\send1{(RULESUSE.IM;1 11504 \count0)}}}\noindent\ifdimen 1wd0>74pt{\hskip-83pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-83pt\box0\hskip0pt plus 1000pt minus 1000pt}}Break if rule is satisfied.

\parshape 1   46pt  416pt {}

\vskip 10pt
\vskip-10pt

\parshape 1  129pt  333pt {}\save0\hbox{\lisp{}BT\rm{}{\send1{(RULESUSE.IM;1 11593 \count0)}}}\noindent\ifdimen 1wd0>74pt{\hskip-83pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-83pt\box0\hskip0pt plus 1000pt minus 1000pt}}Break if rule is tested. Useful for stepping through the execution of a RuleSet.

\parshape 1   46pt  416pt {}


\parshape 1    0pt  462pt {}\parshape 1   46
pt  416pt {}Figure 23.   Compiler options for Breaking and Tracing the execution of RuleSets.       


\parshape 1    0pt  462pt {}


Specifying the declaration \lisp{}Compiler Options: T;\rm{} in a RuleSet indicates that tracing information should be displayed when a rule is satisfied.  To specify the tracing of just an individual rule in the RuleSet, the \lisp{}T\rm{} meta-descriptions should be used as follows:



\lisp{}{\nofill{}{\char'173}T{\char'175}   IF \arg{}cond\lisp{} THEN \arg{}action\lisp{};\par}\rm{}



This tracing specification causes Loops to print a message whenever the LHS of the rule is tested, or the RHS of the rule is executed.  It is also possible to specify that the values of some variables (and compound literals) are to be printed when a rule is traced.  This is done by listing the variables in the \lisp{}Debug Vars\rm{} declaration in the RuleSet:



\lisp{}{\nofill{}Debug Vars: a a:b a:b.c;\par}\rm{}



This will print the values of \lisp{}a\rm{}, \lisp{}a:b\rm{}, and \lisp{}a:b.c\rm{} when any rule is traced or broken.

Analogous specifications are provided for breaking rules.  For example, the declaration \lisp{}Compiler Options: B;\rm{} indicates that Loops is to enter the rule executive (see next section) after the LHS is satisfied and before the RHS is executed.  The rule-specific form:



\lisp{}{\nofill{}{\char'173}B{\char'175}   IF \arg{}cond\lisp{} THEN \arg{}action\lisp{};\par}\rm{}



indicates that Loops is to break before the execution of a particular rule. 

Sometimes it is convenient in debugging to display the source code of a rule when it is traced or broken.  This can be effected by using the \lisp{}PR\rm{}{\send1{(RULESUSE.IM;1 13219 \count0)}} compiler option as in



\lisp{}{\nofill{}Compiler Options: T PR;\par}\rm{}



which prints out the source of a rule when the LHS of the rule is tested and



\lisp{}{\nofill{}Compiler Options: B PR;\par}\rm{}



which prints out the source of a rule when the LHS of a rule is satisfied, and before entering the break. 










\vskip10pt

\bf{}\noindent\save0\hbox{12.10}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Rule Exec

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 13605 \count0)}}\penalty 2000
\mark{The Rule Exec}
\penalty 2000
\vskip10pt
\penalty 2000
A Read-Compile-Evaluate-Print loop, called the rule executive, is provided for the rule language.  The rule executive can be entered during a break by invoking the LISP function \lisp{}RE\rm{}.{\send1{(RULESUSE.IM;1 13806 \count0)}}  During RuleSet execution, the rule executive can be entered by typing \lisp{}{\char'136}f\rm{} (<control>-f) on the keyboard.  

On the first invocation, \lisp{}RE\rm{} prompts the user for a window.  It then displays a stack of RuleSet invocations in a menu to the left of this window in a manner similar to the Interlisp-D Break Package.  Using the left mouse button in this window creates an Inspector window for the work space for the RuleSet.  Using the middle mouse button pretty prints the RuleSet in the default prettyprint window.  

In the main rule executive window, \lisp{}RE\rm{} prompts the user with {\lquotes}\lisp{}re:\rm{}{\rquotes}.  Anything in the rule language (other than declarations) that is typed to this executive will be compiled and executed immediately and its value printed out.  For example, a user may type rules to see whether they execute or variable names to determine their values.  For example:



\lisp{}{\nofill{}re: trafficLight:color
Red
re:\par}\rm{}



this example shows how to get the value of the \lisp{}color\rm{} variable of the \lisp{}trafficLight\rm{} object.  If the value of a variable was set by a RuleSet running with auditing, then a \lisp{}why\rm{} question can be typed to the rule executive as follows:



\lisp{}{\nofill{}re: why trafficLight:color

IF highLight:color = 'Green  farmRoadSensor:cars timer.TL
THEN highLight:color {\char'137} 'Yellow  timer.Start;

Rule 3 of RuleSet LightRules
Edited: Conway "13-Oct-82"

re:\par}\rm{}



The rule executive may be exited by typing \lisp{}OK\rm{}.









\vskip10pt

\bf{}\noindent\save0\hbox{12.11}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Auditing RuleSets

\rm{}\penalty 2000
{\send1{(RULESUSE.IM;1 15339 \count0)}}\penalty 2000
\mark{Auditing RuleSets}
\penalty 2000
\vskip10pt
\penalty 2000
Two declarations at the beginning of a RuleSet affect the auditing.  Auditing is turned on by the compiler option \lisp{}A\rm{}.{\send1{(RULESUSE.IM;1 15499 \count0)}}  The simplest form of this is



\lisp{}{\nofill{}Compiler Options: A;\par}\rm{}



The \lisp{}Audit Class\rm{} declaration indicates the class of the audit record to be used with this RuleSet if it is compiled in \sl{}audit\rm{} mode.



\lisp{}{\nofill{}Audit Class: StandardAuditRecord;\par}\rm{}



A \lisp{}Meta Assignments\rm{} declaration can be used to indicate the audit description to be used for the rules unless overridden by a rule-specific meta-assignment statement in braces.



\lisp{}{\nofill{}Meta Assignments: ( cf{\char'137}.5 support{\char'137}'GroundWff);\par}\rm{}


 





 











\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{13}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}USING THE LOOPS SYSTEM

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 76 \count0)}}\penalty 2000
\mark{USING THE LOOPS SYSTEM}
\penalty 2000
\vskip10pt
\penalty 2000
Loops is integrated with Interlisp-D, and makes use of many of its advanced features.  In order to run Loops one must have the appropriate version of the Interlisp-D system and the corresponding versions of a set of LispUsers packages.  The instructions for building the system as of February 1, 1983 are contained in a document of export instructions, currently filed on: \lisp{}{\char'173}MAXC{\char'175}<LOOPS>EXPORTINSTRUCTIONS.TXT\rm{}. 




\vskip10pt

\bf{}\noindent\save0\hbox{13.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Starting up the System

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 573 \count0)}}\penalty 2000
\mark{Starting up the System}
\penalty 2000
\vskip10pt
\penalty 2000
At PARC, we maintain two version of Loops most of the time, a current system which is a released version, an another which is the system under development. There are two command files: \lisp{}loops.cm\rm{} and \lisp{}newLoops.cm\rm{} which start up a Lisp and fetch the appropriate sysout from a server.

In the version of the system as loaded at PARC, we include the following Lispusers packages: \lisp{}TTY\rm{}, \lisp{}TMENU\rm{}, \lisp{}GRAPHER\rm{}, \lisp{}HISTMENU\rm{}, \lisp{}SINGLEFILEINDEX\rm{}, \lisp{}PATCHUP\rm{}

The first four packages must be included in any loadup of Loops; the second are ones we find useful.  Documentation of these facilities are to be found on \lisp{}<LISPUSERS>\rm{} directories on various servers.










\vskip10pt

\bf{}\noindent\save0\hbox{13.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Loops Screen Setup

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 1384 \count0)}}\penalty 2000
\mark{The Loops Screen Setup}
\penalty 2000
\vskip10pt
\penalty 2000
The screen as one sees it set up contains the following windows(top to bottom, left to right):

\sl{}Prompt Window\rm{} --- Small black window in upper left.  Prompts for what will happen in various mouse interactions appear here.  Also various notifications of directory attachment changes.  Labelled with the date of the Lisp system loadup and of the Loops system loadup.

\sl{}Top Level Window\rm{} --- Normal interaction window.  Labelled with the currently connected directory.

\sl{}User Exec -- PPDefault Window\rm{} --- Below the EditCommands menu is a title icon of the UserExec window.  When this is expanded it fills the bottom half of the screen.  It can be used for TTY interactions.  It can be made the primary window for such interactions by calling the function \lisp{}UE\rm{}.{\send1{(USINGLOOPS.IM;7 2170 \count0)}}  Typing \lisp{}OK\rm{} when in that window returns you to the previous \lisp{}TTYDIPLAYSTREAM\rm{}.   This window is also used as the default place to prettyprint class and instance descriptions.

There are three icons on the right half of the screen.

\sl{}Loops Icon\rm{} --- This circular icon is active and if buttoned gives the user the option of setting up the screen again (useful if it has been cluttered with many windows), and of producing a graph browser of the current classes in the system.

\sl{}History Icon\rm{} --- This icon will expand to give a History menu list.  See the write up on \lisp{}<LISPUSERS>HISTMENU.TTY\rm{}.

\sl{}Edit Work Area\rm{} --- This window is shown only by a title icon in the upper right.  It expands when necessary, and takes up the entire right half of the screen.  It shrinks automatically when \lisp{}DoneEdit\rm{} is selected from the EditCommand menu.  It can be expanded to allow you to look at the last expression being edited.









\vskip10pt

\bf{}\noindent\save0\hbox{13.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Using the Browser

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 3221 \count0)}}\penalty 2000
\mark{Using the Browser}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(USINGLOOPS.IM;7 3241 \count0)}}





Two special classes in the system are used to build browsers based on the grapher package.  The general class is called \lisp{}LatticeBrowser\rm{}, and the particular subClass that is used by the system is called \lisp{}ClassBrowser\rm{}.  We will first describe how to use the class browser which appears when requested by buttoning in the Loops icon.  We then describe how to build your own browser.





\vskip10pt

\bf{}\noindent\save0\hbox{13.3.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Using the Class Browser

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 3763 \count0)}}\penalty 2000
\mark{Using the Class Browser}
\penalty 2000
\vskip10pt
\penalty 2000
The items in the class browser can be buttoned with either the left or middle button.  When buttoned a pop up menu will appear, and the user can make a selection of one of these.

If a browser menu selection is followed by an asterisk (i.e., \lisp{}Print*\rm{}), this means that it has a number of sub-commands.  Selecting such a selection with the middle mouse button will present another pop-up menu of sub-commands.  Selecting a {\lquotes}starred{\rquotes} selection with the left mouse button will execute the {\lquotes}default{\rquotes} sub-command.  The left and middle mouse buttons act the same when selecting an un-starred selection.

The left button menu selections are:



\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Print*\rm{}{\send1{(USINGLOOPS.IM;7 4507 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Prints a summary of information about the selected class in the {\lquotes}User Exec -- PPDefault Window{\rquotes}.  If selected with the middle mouse button, another pop-up menu gives a choice of what to print:



\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}PP\rm{}{\send1{(USINGLOOPS.IM;7 4811 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}PrettyPrint Class definition.


\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}PP!\rm{}{\send1{(USINGLOOPS.IM;7 4897 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}PrettyPrint Class definition including inherited information.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166
pt  296pt {}\save0\hbox{\lisp{}PPV!\rm{}{\send1{(USINGLOOPS.IM;7 5017 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Same as \lisp{}PP!\rm{} without seeing methods.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}PPM\rm{}{\send1{(USINGLOOPS.IM;7 5116 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Puts up a pop-up menu of all of the methods defined in the class, and prettyprints the definition of the selected one.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt

\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}PrintSummary\rm{}{\send1{(USINGLOOPS.IM;7 5309 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Prints a summary of all of the information (instance variables, class variables, and methods) for the selected class

\parshape 1   92pt  370pt {}

If \lisp{}Print*\rm{} is selected with the left button, \lisp{}PrintSummary\rm{} is the default sub-command that is executed.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92
pt  370pt {}\save0\hbox{\lisp{}Doc*\rm{}{\send1{(USINGLOOPS.IM;7 5660 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Prints documentation for Classes, IVs, CVs, or Methods.  If selected with the middle mouse button, another pop-up menu gives a choice of what to print:



\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}ClassDoc\rm{}{\send1{(USINGLOOPS.IM;7 5933 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Prints Class doc information for selected class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}MethodDoc\rm{}{\send1{(USINGLOOPS.IM;7 6050 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Puts up a pop-up menu of all of the methods defined in the class, and prints the doc information of the selected one.  This pop-up menu is redisplayed until the user buttons outside the menu, so that the user can see the doc information from multiple methods.


\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}IVDoc\rm{}{\send1{(USINGLOOPS.IM;7 6370 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Same as \lisp{}MethodDoc\rm{}, except that it prints the doc information for instance variables of the class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166
pt  296pt {}\save0\hbox{\lisp{}CVDoc\rm{}{\send1{(USINGLOOPS.IM;7 6535 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Same as \lisp{}MethodDoc\rm{}, except that it prints the doc information for class variables of the class.

\parshape 1   92pt  370pt {}

If \lisp{}Doc*\rm{} is selected with the left button, \lisp{}ClassDoc\rm{} is the default sub-command that is executed.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}WhereIs\rm{}{\send1{(USINGLOOPS.IM;7 6868 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}This command is used to find out which super class of the selected class a particular IV, CV, or Method was inherited from.  When selected with the left or middle mouse button, a pop-up menu is displayed with the elements \lisp{}IVS\rm{}, \lisp{}CVS\rm{}, \lisp{}Methods\rm{}.  Whichever element is selected, a pop-up menu of the class' instance variables (or class variables or methods) is displayed.  When one of these is selected, the super class from which that IV, CV or Method was inherited is flashed, and its nameis printed in the Prompt Window.  This final pop-up menu is redisplayed until the user buttons outside the menu, so that the user select multiple IVs (or CVs or methods).



\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Unread\rm{}{\send1{(USINGLOOPS.IM;7 7608 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Unreads \lisp{}{\char'44}\arg{}className\lisp{}\rm{} into the typein buffer.  This is useful when typing messages to particular classes.


\parshape 1    0pt  462pt {}



The middle button menu selections are:



\vskip 10pt
\vskip-10pt
\parshape 1   92
pt  370pt {}\save0\hbox{\lisp{}EM*\rm{}{\send1{(USINGLOOPS.IM;7 7922 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Edit a method in the selected class.  If selected with the middle mouse button, puts up another pop-up menu:



\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}EM\rm{}{\send1{(USINGLOOPS.IM;7 8139 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Puts up a pop-up menu of all of the methods defined in the class, and envokes the editor on the selected method.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}EM!\rm{}{\send1{(USINGLOOPS.IM;7 8308 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Same as \lisp{}EM\rm{}, except that includes all inherited methods in the list.


\parshape 1   92pt  370pt {}

If \lisp{}EM*\rm{} is selected with the left button, \lisp{}EM\rm{} is the default sub-command that is executed.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Add*\rm{}{\send1{(USINGLOOPS.IM;7 8600 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Add a new method, a specialized class, an IV, or a CV to the selected class, or make a new instance.  If selected with the middle mouse button, puts up another pop-up menu:



\vskip 10pt
\vskip-10pt
\parshape 1  166
pt  296pt {}\save0\hbox{\lisp{}Specialize\rm{}{\send1{(USINGLOOPS.IM;7 8898 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Creates a new subclass of the selected class, giving it a name typed by the user.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}DefMethod\rm{}{\send1{(USINGLOOPS.IM;7 9048 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Define a new method to the selected class.  Asks the user (in the prompt window) to type the name of a selector, and envokes the editor on a dummy definition for that new method.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt

\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}DefRSM\rm{}{\send1{(USINGLOOPS.IM;7 9289 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Installs a RuleSet as a method in a class.  Asks the user (in the prompt window) to type the name of a selector, and invokes the RuleSet editor.  When the user exits the RuleSet editor, the RuleSet is compiled and installed as the method in the class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}AddIV\rm{}{\send1{(USINGLOOPS.IM;7 9601 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Asks the user to type an instance variable name, and adds it to the selected class.

\parshape 1   92
pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}AddCV\rm{}{\send1{(USINGLOOPS.IM;7 9745 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Asks the user to type a class variable name, and adds it to the selected class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}New\rm{}{\send1{(USINGLOOPS.IM;7 9881 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Sets the Interlisp variable \lisp{}IT\rm{}{\send1{(USINGLOOPS.IM;7 9939 \count0)}} to a new instance of the selected class.


\parshape 1   92pt  370pt {}

If \lisp{}Add*\rm{} is selected with the left button, \lisp{}DefMethod\rm{} is the default sub-command that is executed.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Delete\rm{}{\send1{(USINGLOOPS.IM;7 10204 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Delete a method, IV, or CV from the selected, or the whole selected class.  Puts up a pop-up menu with elements \lisp{}IVs\rm{}, \lisp{}CVs\rm{}, \lisp{}Methods\rm{}, and \lisp{}Class\rm{}.  If one of the first three is selected, a menu of the selected class' instance variables, class variables, or methods is given, and the selected one is deleted from the class.  If \lisp{}Class\rm{} is selected, the whole class is deleted.


\parshape 1    0
pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Move*\rm{}{\send1{(USINGLOOPS.IM;7 10669 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Move or copy an IV, CV, method, or super from the selected class to another class.  The destination class is specified by using the \lisp{}BoxNode\rm{} command, described below.  If selected with the middle mouse button, puts up another pop-up menu:



\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}MoveTo\rm{}{\send1{(USINGLOOPS.IM;7 11032 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Puts up a pop-up menu with elements \lisp{}IVS\rm{}, \lisp{}CVS\rm{}, \lisp{}Methods\rm{}, and \lisp{}Supers\rm{}.  Selecting one of these will put up still another menu, listing the items of that type.  Selecting one of these items will cause it to be moved to the destination class specified with \lisp{}BoxNode\rm{}. 


\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt

\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}CopyTo\rm{}{\send1{(USINGLOOPS.IM;7 11391 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}The same as \lisp{}MoveTo\rm{}, except that the selected item is copied to the destination class.

\parshape 1   92pt  370pt {}

If \lisp{}Move*\rm{} is selected with the left button, \lisp{}MoveTo\rm{} is the default sub-command that is executed.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92
pt  370pt {}\save0\hbox{\lisp{}BoxNode\rm{}{\send1{(USINGLOOPS.IM;7 11715 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Draws a box around the selected class node.  If the selected class is already boxed, the box is removed.  If any other class node has been boxed, that box is removed.  This command is used in conjunction with the \lisp{}Move*\rm{} command to specify a {\lquotes}destination class{\rquotes}, as described above.

\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Rename*\rm{}{\send1{(USINGLOOPS.IM;7 12067 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Renames some part of the selected class.  Puts up a pop-up menu with elements \lisp{}IVS\rm{}, \lisp{}CVS\rm{}, \lisp{}Methods\rm{}, and \lisp{}Class\rm{}.  Selecting one of these will put up still another menu, listing the items of that type.  Selecting one of these items will cause it to be renamed to a name typed in by the user.




\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt

\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}Edit*\rm{}{\send1{(USINGLOOPS.IM;7 12491 \count0)}}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Edit some part of the selected class.    If selected with the middle mouse button, puts up another pop-up menu:



\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}EditObject\rm{}{\send1{(USINGLOOPS.IM;7 12729 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Calls the editor to edit the selected class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166
pt  296pt {}\save0\hbox{\lisp{}EditIVs\rm{}{\send1{(USINGLOOPS.IM;7 12838 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Calls the editor to edit the instance variables of the selected class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt
\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}EditCVs\rm{}{\send1{(USINGLOOPS.IM;7 12973 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Calls the editor to edit the class variables of the selected class.

\parshape 1   92pt  370pt {}

\vskip 10pt
\vskip-10pt

\parshape 1  166pt  296pt {}\save0\hbox{\lisp{}Inspect\rm{}{\send1{(USINGLOOPS.IM;7 13105 \count0)}}}\noindent\ifdimen 1wd0>66pt{\hskip-74pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-74pt\box0\hskip0pt plus 1000pt minus 1000pt}}Call the Interlisp inspector to inspect the selected class.

\parshape 1   92pt  370pt {}

If \lisp{}Edit*\rm{} is selected with the left button, \lisp{}EditObject\rm{} is the default sub-command that is executed.


\parshape 1    0pt  462pt {}


Pressing either the left or middle mouse button in the title region at the top of the class browser brings up another pop-menu, containing commands which deal with the entire browser.  The commands are:



\vskip 10pt
\vskip-10pt
\parshape 1   92
pt  370pt {}\save0\hbox{\lisp{}Recompute\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Recompute class lattice from the {\lquotes}starting list{\rquotes} of objects (described below).


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}AddRoot\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Add named item to starting list for browser.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt

\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}DeleteRoot\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Delete named item from starting list for browser.


\parshape 1    0pt  462pt {}

\vskip 10pt
\vskip-10pt
\parshape 1   92pt  370pt {}\save0\hbox{\lisp{}SaveInIT\rm{}}\noindent\ifdimen 1wd0>82pt{\hskip-92pt\box0\hskip0pt plus 1000pt\linebreak\null}\else{\hbox to 0pt{\hskip-92pt\box0\hskip0pt plus 1000pt minus 1000pt}}Store this browser object in the Interlisp variable \lisp{}IT\rm{}.


\parshape 1    0
pt  462pt {}



To create a Class Browser for a small set of classes, send the message \lisp{}Show\rm{} to the class \lisp{}ClassBrowser\rm{}:



\lisp{}{\nofill{}({\char'137}New ({\char'44} ClassBrowser) Show \arg{}browseList\lisp{} \arg{}window\lisp{})\par}\rm{}



This displays the class inheritance lattice starting with the {\lquotes}starting list{\rquotes} of objects \arg{}browseList\rm{}.  \arg{}browseList\rm{} can be a single className or class, or a list of these.  A new browse window will be created which contains nodes for each class mentioned, and (recursively) all subclasses of those classes in the current environment which have been accessed.  If \arg{}window\rm{} is given, then it will be used as the display window.












\vskip10pt

\bf{}\noindent\save0\hbox{13.3.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Building Your Own Browser

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 14916 \count0)}}\penalty 2000
\mark{Building Your Own Browser}
\penalty 2000
\vskip10pt
\penalty 2000
* * * The following information is incorrect.  If you want to build your own browser, try poking around the class \lisp{}LatticeBrowser\rm{}.  Good Luck. * * *


The general class which supports browsing is \lisp{}LatticeBrowser\rm{}.{\send1{(USINGLOOPS.IM;7 15173 \count0)}}  The specialization \lisp{}ClassBrowser\rm{}{\send1{(USINGLOOPS.IM;7 15241 \count0)}} is used to generate the Class Inheritance Lattice Browser that we all use.  \lisp{}ClassBrowser\rm{} provides an example of how to specialize \lisp{}LatticeBrowser\rm{} for your own use.  The following is a brief description of the \lisp{}LatticeBrowser\rm{} messages.

If \lisp{}({\char'44} Lb)\rm{} is an instance of (any subclass of) \lisp{}({\char'44} LatticeBrowser)\rm{} then:



\lisp{}{\nofill{}({\char'137} ({\char'44} Lb) Show \arg{}browseList\lisp{})\par}\rm{}



will create a graph of elements starting with those in \arg{}browseList\rm{}.  \arg{}browseList\rm{} should be a list of objectNames or objects.  If \arg{}browseList\rm{} is single item, it will be treated as list of that item. The browser will show a lattice of elements determined by a sub relation implemented by the \lisp{}LatticeBrowser\rm{} message \lisp{}GetSub\rm{}.  For each object, \lisp{}({\char'137} ({\char'44} Lb) GetSubs \arg{}object\lisp{})\rm{} should produce a list of objects which are the {\lquotes}subs{\rquotes} of \arg{}object\rm{}, and \lisp{}({\char'137} ({\char'44} Lb) GetLabel \arg{}object\lisp{})\rm{} should produce a string to be used in the graph as a label.  The \lisp{}GetSubs\rm{} method in \lisp{}LatticeBrowser\rm{} just obtains the value of the instance variable \lisp{}sub\rm{}, if it exists in that object (no error otherwise).  The \lisp{}GetLabel\rm{} method in \lisp{}LatticeBrowser\rm{} finds the name of the object. 

Each node in the browser graph has actions associated with the left and middle mouse buttons.  When either button is clicked over a node, a menu of actions is brought up.  The items on the action menu are determined by the class variables \lisp{}LeftButtonItems\rm{}{\send1{(USINGLOOPS.IM;7 16764 \count0)}} and \lisp{}MiddleButtonItems\rm{}.{\send1{(USINGLOOPS.IM;7 16842 \count0)}}  

The value obtained by selecting the menu item will be used as a message selector for an action.  The message will be sent either to the browser or to the object itself.  Selectors on the class variable \lisp{}LocalCommands\rm{},{\send1{(USINGLOOPS.IM;7 17113 \count0)}} or those not understood by the object will be sent in a message to the browser, with arguments of the object and objectName.  Otherwise, the object will be sent that selector as a unary message (no arguments).

For example, assume that the value of \lisp{}LeftButtonItems\rm{} was \lisp{}(PP PP! EditObject)\rm{} and the value of \lisp{}LocalCommands\rm{} was \lisp{}NIL\rm{}, and \lisp{}EditObject\rm{} is not understood by \arg{}obj1\rm{} selected in the browser.  By buttoning \lisp{}PP\rm{} (or \lisp{}PP!\rm{}) in the action menu, \arg{}obj1\rm{} would be sent the message \lisp{}PP\rm{} (or \lisp{}PP!\rm{}).  Selecting \lisp{}EditObject\rm{} would result in sending the message \lisp{}({\char'137} ({\char'44} Lb) EditObject \arg{}obj1\lisp{} (GetName \arg{}obj1\lisp{}))\rm{}.

A \lisp{}LatticeBrowser\rm{} responds to \lisp{}EditObject\rm{} by sending the object the message \lisp{}Edit\rm{} \sl{}in a TTY process\rm{}.  The latter is necessary to allow the mouse to continue to work in the process world.  If \arg{}obj1\rm{} might have understood the message \lisp{}EditObject\rm{}, then that atom should appear on the list \lisp{}LocalCommands\rm{} to ensure that the browser is sent the message rather than \arg{}obj1\rm{}.

As usual with menus, items need not be atoms.  If an item is a list, EVAL of the second element is returned.  Thus one might have the element \lisp{}("Edit With EE" 'EEObject )\rm{} on a menu item list, so the string \lisp{}"Edit With EE"\rm{} will be displayed in the Menu, and the message \lisp{}EEObject\rm{} sent when that item is selected.

If the result of selecting an item returns a list, the \lisp{}CAR\rm{} of the list is treated as the selector, and \lisp{}CDR\rm{} is an extra argument to send.  For example, in the class browser \lisp{}MiddleButtonItems\rm{} contains an item \lisp{}(EditIVs '(EditObject -2 EE))\rm{}.  Selecting \lisp{}EditIVs\rm{} in the menu causes the following message to be sent: \lisp{}({\char'137} ({\char'44} Lb EditObject \arg{}object\lisp{} (-2 EE))\rm{}

\sl{}Shifted Selections\rm{} --- If one selects a node with the \lisp{}LEFT\rm{} or \lisp{}MIDDLE\rm{} mouse button while holding down the left shift key, then a message is sent to the browser:



\lisp{}{\nofill{}({\char'137} ({\char'44} Lb) LeftShiftSelect \arg{}object\lisp{} \arg{}objName\lisp{})
({\char'137} ({\char'44} Lb) MiddleShiftSelect \arg{}object\lisp{} \arg{}objName\lisp{})\par}\rm{}



The default behavior for \lisp{}LeftShiftSelect\rm{}{\send1{(USINGLOOPS.IM;7 19334 \count0)}} is to send \lisp{}PP!\rm{} to the object, and for \lisp{}MiddleShiftSelect\rm{}{\send1{(USINGLOOPS.IM;7 19456 \count0)}} to send \lisp{}EEObject\rm{} to the browser.


\sl{}Moving Nodes\rm{} --- Holding the \lisp{}CTRL\rm{} key down when selecting allows one to move the selected node in the browser window.  This does not affect the underlying structure, just the display.

\sl{}Format of the Browser Window\rm{} --- One can obtain a browser display with a specified title or in an existing window.  If one specifies \arg{}windowOrTitle\rm{} in



\lisp{}{\nofill{}({\char'137} ({\char'44} Lb) Show \arg{}browseList\lisp{} \arg{}windowOrTitle\lisp{})\par}\rm{}



then if \arg{}windowOrTitle\rm{} is a string, it will be used as the title of a new window for the browser.  If \arg{}windowOrTitle\rm{} is a window, then that window will be used as is.  If \arg{}windowOrTitle\rm{}=\lisp{}NIL\rm{}, then the title is obtained from the instance variable \lisp{}title\rm{},{\send1{(USINGLOOPS.IM;7 20239 \count0)}} and a new window is created and stored in the instance variable \lisp{}window\rm{}.{\send1{(USINGLOOPS.IM;7 20355 \count0)}}  If the instance variable \lisp{}topAlign\rm{}=\lisp{}T\rm{}{\send1{(USINGLOOPS.IM;7 20445 \count0)}} (the default) then GRAPHER will align the graph to the top of the window.  The font used for labels is found in the instance variable \lisp{}browseFont\rm{}.{\send1{(USINGLOOPS.IM;7 20639 \count0)}}  At any time, the last object selected is found in \lisp{}lastSelectedObject\rm{}.{\send1{(USINGLOOPS.IM;7 20766 \count0)}}


\sl{}SUMMARY:\rm{}  To specialize a browser, define the method for \lisp{}GetSubs\rm{}.  If the browser is not using object names for its labels, specialize \lisp{}GetLabel\rm{}.  Set up the class variables \lisp{}LeftButtonItems\rm{}, \lisp{}MiddleButtonItems\rm{} and \lisp{}LocalCommands\rm{}.  Specialize \lisp{}LeftShiftSelect\rm{} and \lisp{}MiddleShiftSelect\rm{} if desired.




\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21161 \count0)}}\formatdef{462pt}{\lisp{}LatticeBrowser\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}

IV's:



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21229 \count0)}}\formatdef{462pt}{\lisp{}boxedNode\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent The last object boxed, if any.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21323 \count0)}}\formatdef{462pt}{\lisp{}browseFont\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent The font used for labels.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21420 \count0)}}\formatdef{462pt}{\lisp{}lastSelectedObject\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Last object selected.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21507 \count0)}}\formatdef{462pt}{\lisp{}startingList\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent List of objects used to compute this browser.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21611 \count0)}}\formatdef{462pt}{\lisp{}title\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Title passed to GRAPHER package.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21705 \count0)}}\formatdef{462pt}{\lisp{}topAlign\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Flag used to indicate whether graph should be aligned with the top or bottom of the window.  If \lisp{}topAlign\rm{}=\lisp{}T\rm{} (the default) then GRAPHER will align the graph to the top of the window.


\parshape 1    0
pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 21959 \count0)}}\formatdef{462pt}{\lisp{}window\rm{}}{IV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Window for browsing.


\parshape 1    0pt  462pt {}

CVs:



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 22054 \count0)}}\formatdef{462pt}{\lisp{}LeftButtonItems\rm{}}{CV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Items for left button menu.  Value sent as message to object or browser.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 22193 \count0)}}\formatdef{462pt}{\lisp{}LocalCommands\rm{}}{CV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent List of messages that should be sent to browser when item is selected in menu, even if object does understand them.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 22379 \count0)}}\formatdef{462pt}{\lisp{}MiddleButtonItems\rm{}}{CV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Items for middle button menu.  Value sent as message to object or browser.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 22517 \count0)}}\formatdef{462pt}{\lisp{}TitleItems\rm{}}{CV of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Items for menu in title of window.


\parshape 1    0pt  462pt {}

Methods:



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 22706 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} BoxNode \arg{}object\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Draws a box around the node in the graph representing the object.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 22974 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} DoSelectedCommand \arg{}command\lisp{} \arg{}obj\lisp{} \arg{}objName\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Does the selected command or forwards it to the object.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(USINGLOOPS.IM;7 23199 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} EEObject \arg{}object\lisp{} \arg{}objName\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Edit \arg{}object\rm{}, using the TTYIN editor (in a \lisp{}TTYPROCESS\rm{}).


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 23455 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} EditObject \arg{}object\lisp{} \arg{}objName\lisp{} \arg{}args\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Edit \arg{}object\rm{} using Lisp editor (in a \lisp{}TTYPROCESS\rm{}), passing the commands \arg{}args\rm{}.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 23730 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} FlashNode \arg{}node\lisp{} \arg{}N\lisp{} \arg{}flashTime\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Call \lisp{}FlipNode\rm{} 2\arg{}N\rm{} times, delaying for \arg{}flashTime\rm{} milliseconds between flips.  Default values: \arg{}N\rm{}=3, \arg{}flashTime\rm{}=300.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 24020 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} FlashNode \arg{}object\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Inverts the video around the node in the graph representing \arg{}object\rm{}.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 24240 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} GetLabel \arg{}object\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the label for \arg{}object\rm{} displayed in the browser.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 24485 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} GetNodeList \arg{}browseList\lisp{} \arg{}goodList\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Returns the node data structures of the tree starting at \arg{}browseList\rm{}.  If \arg{}goodList\rm{} is given, only include elements of it.  If \arg{}goodList\rm{}=\lisp{}T\rm{}, this is the same as \arg{}goodList\rm{}=\arg{}browseList\rm{}.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 24844 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} GetSubs \arg{}object\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns a list of the subs from \arg{}object\rm{}.


\parshape 1    0
pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 25072 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} LeftShiftSelect \arg{}object\lisp{} \arg{}objname\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Called when \arg{}object\rm{} is selected with the \lisp{}LEFT\rm{} mouse button while the shift key is down.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 25358 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} MiddleShiftSelect \arg{}object\lisp{} \arg{}objname\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Called when \arg{}object\rm{} is selected with the \lisp{}MIDDLE\rm{} mouse button while the shift key is down.



\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 25618 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} ObjNamePair \arg{}objOrName\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}objOrName\rm{} may be either an object or a name used to label an object in the browser.  Returns the pair \lisp{}(\arg{}object\lisp{} . \arg{}objName\lisp{})\rm{}.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 25893 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} Recompute)\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Recompute the browser display using same window and \arg{}browseList\rm{}


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 26166 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} Show \arg{}browseList\lisp{} \arg{}windowOrTitle\lisp{} \arg{}goodList\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Show the items and their subs on a browse window.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(USINGLOOPS.IM;7 26380 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}browser\lisp{} Unread \arg{}object\lisp{} \arg{}objName\lisp{})\lisp{}\rm{}}{Method of LatticeBrowser}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Put \lisp{}{\char'44}\arg{}objName\lisp{}\rm{} into the tty buffer


\parshape 1    0pt  462pt {}















\vskip10pt

\bf{}\noindent\save0\hbox{13.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Editing in Loops

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 26571 \count0)}}\penalty 2000
\mark{Editing in Loops}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(USINGLOOPS.IM;7 26591 \count0)}}


This section is about editing in Loops.  It describes the Loops interface to the standard Interlisp editors.  In addition to the usual teletype oriented editor, Interlisp-D, provides a variety of other editing programs that make available the benefits of a bitmap display and a mouse.  We will describe some of the interfaces to these editors, but leave the instruction on editing to the appropriate other documents




\vskip10pt

\bf{}\noindent\save0\hbox{13.4.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Editing a Class

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 27072 \count0)}}\penalty 2000
\mark{Editing a Class}
\penalty 2000
\vskip10pt
\penalty 2000
The editor for classes is invoked by sending the message \lisp{}Edit\rm{}{\send1{(USINGLOOPS.IM;7 27165 \count0)}} to the class to be edited.  The message \lisp{}Edit\rm{} allows an optional argument, a list of editing commands, as do all the usual Lisp editing functions.

Example:  To edit \lisp{}StudentEmployee\rm{}:



\lisp{}{\nofill{}({\char'137} ({\char'44} StudentEmployee) Edit)\par}\rm{}



An alternative way to edit a class is provided by the LISP function \lisp{}EC\rm{}{\send1{(USINGLOOPS.IM;7 27492 \count0)}} (for {\lquotes}edit class{\rquotes}).  \lisp{}EC\rm{} takes the class name as its argument.  For this example, the form is:

\lisp{}(EC ({\char'44} StudentEmployee))\rm{}

At this point, if you prettyprint the expression you will see:



\lisp{}{\nofill{}[DEFCLASS StudentEmployee
   (MetaClass Class)
   (Supers Student Employee)
   (InstanceVariables)
   (ClassVariables)
   (Methods)]\par}\rm{}



Suppose now you edit this structure to the one shown below:



\lisp{}{\nofill{}[DEFCLASS StudentEmployee
   (MetaClass Class)
   (Supers Student Employee)
   (InstanceVariables   (name) 
                     (project "KBE"))
   (ClassVariables   (numberEmployees 0))
   (Methods         (Work StudentEmployee.Work))\par}\rm{}



This specifies that each instance will have two instance variables, \lisp{}name\rm{} and \lisp{}project\rm{}, with default values of \lisp{}NIL\rm{} and \lisp{}"KBE"\rm{}, respectively.  The class has a class variable \lisp{}numberEmployees\rm{}, initialized to \lisp{}0\rm{}.   If we have an instance of this class bound to the Lisp variable \lisp{}worker\rm{}, the following expression causes this instance to respond to the message \lisp{}Work\rm{}: 



\lisp{}{\nofill{}({\char'137} worker Work 3)\par}\rm{}



The result of evaluating this expression is to call the Lisp function \lisp{}StudentEmployee.Work\rm{} with arguments (the value of) \lisp{}worker\rm{} and 3.  This is described in more detail in the section on methods.

The normal way to terminate editing is with \lisp{}OK\rm{}.  This causes the revised definition to be installed.  If you exit from this editing session with \lisp{}STOP\rm{} or {\char'136}D, all the changes of this session will be lost, since the list structure is not saved; it is only used to build the new class structure.  If you have made any syntax errors in editing, warning messages will be printed when you type \lisp{}OK\rm{}, and you will be returned to the editor.









\vskip10pt

\bf{}\noindent\save0\hbox{13.4.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Editing an Instance

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 29355 \count0)}}\penalty 2000
\mark{Editing an Instance}
\penalty 2000
\vskip10pt
\penalty 2000
To edit an instance, send it the message \lisp{}Edit\rm{}.{\send1{(USINGLOOPS.IM;7 29432 \count0)}}  



\lisp{}{\nofill{}({\char'137} \arg{}object\lisp{} Edit)\par}\rm{}



This will put you in the Interlisp editor editing a source for the instance.  When you end with \lisp{}OK\rm{}, the new values will be inserted in the instance.  

An equivalent way to edit an instance is



\lisp{}{\nofill{}(EI \arg{}object\lisp{})\par}\rm{}

{\send1{(USINGLOOPS.IM;7 29712 \count0)}}

where \arg{}object\rm{} is an instance.  (If one has an Interlisp variable, say \lisp{}X1\rm{}, bound to an instance then to edit one should type \lisp{}(EI X1)\rm{}. 

When instances refer to other instances, they are printed out in the form \lisp{}{\char'43}"UI&DII"\rm{}, that is as a hash mark (\lisp{}{\char'43}\rm{}) followed by a string which is a unique identifier.  When this is read back in from the string editing buffer of TTYIN, a readmacro for \lisp{}{\char'43}\rm{} converts it back into a pointer to an instance with that unique identifier.  When a class is printed out for TTYIN it prints as \lisp{}{\char'43}{\char'44}ClassName\rm{}, and the \lisp{}{\char'43}\rm{} readmacro converts it bvack into a pointer to the class.








\vskip10pt

\bf{}\noindent\save0\hbox{13.4.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Editing a Method

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 30459 \count0)}}\penalty 2000
\mark{Editing a Method}
\penalty 2000
\vskip10pt
\penalty 2000
Often it is convenient to type to enter only a skeletal definition for a method, and then finish making the specifications by using an editor.  To edit the function for a particular method:



\lisp{}{\nofill{}(EM \arg{}className\lisp{} \arg{}selector\lisp{})\par}\rm{}

{\send1{(USINGLOOPS.IM;7 30712 \count0)}}

This puts you in the Lisp editor, editing whatever function is associated with the selector specified. The name of the actual function is printed out as you enter the editing process.  Aside from the syntactic convention of having the first argument to a function implementing a method be \lisp{}self\rm{}, these methods are perfectly normal Lisp functions.  However, special compilations can be done on these using the GLISP compiler for Loops.  This is documented in the section on Lisp interactions.















\vskip10pt

\bf{}\noindent\save0\hbox{13.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Inspecting in Loops

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 31478 \count0)}}\penalty 2000
\mark{Inspecting in Loops}
\penalty 2000
\vskip10pt
\penalty 2000
Loops is integrated into the Lisp system so that one can invoke the Inspector on Loops objects.  This uses the Loops inspect package, which allows a specialized way of viewing the objects in Loops terms as described in the two sections below. 



\vskip10pt

\bf{}\noindent\save0\hbox{13.5.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Inspecting Classes

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 31792 \count0)}}\penalty 2000
\mark{Inspecting Classes}
\penalty 2000
\vskip10pt
\penalty 2000
To inspect a class, send the message \lisp{}Inspect\rm{}:{\send1{(USINGLOOPS.IM;7 31871 \count0)}}



\lisp{}{\nofill{}({\char'137} ({\char'44} \arg{}className\lisp{}) Inspect)\par}\rm{}










\vskip10pt

\bf{}\noindent\save0\hbox{13.5.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Inspecting Instances

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 32022 \count0)}}\penalty 2000
\mark{Inspecting Instances}
\penalty 2000
\vskip10pt
\penalty 2000
An alternative way to modify an instance is to inspect it:



\lisp{}{\nofill{}({\char'137} \arg{}object\lisp{} Inspect)\par}\rm{}



and then you can set any values and properties, and add or delete any IVs.
















\vskip10pt

\bf{}\noindent\save0\hbox{13.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Errors in Loops

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 32357 \count0)}}\penalty 2000
\mark{Errors in Loops}
\penalty 2000
\vskip10pt
\penalty 2000
Most errors in Loops which are not errors in Lisp call the function \lisp{}HELPCHECK\rm{},{\send1{(USINGLOOPS.IM;7 32462 \count0)}} which prints out a message, and goes into a Lisp break.  The appropriate response to some errors is described below.




\vskip10pt

\bf{}\noindent\save0\hbox{13.6.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}When the Object is Not Recognized

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 32678 \count0)}}\penalty 2000
\mark{When the Object is Not Recognized}
\penalty 2000
\vskip10pt
\penalty 2000
When the value of \arg{}object\rm{} in the form



\lisp{}{\nofill{}({\char'137} \arg{}object\lisp{} \arg{}selector\lisp{} \arg{}arg\sub{1}\lisp{} $\cdots$ \arg{}arg\sub{N}\lisp{})\par}\rm{}



is not a Loops object, Loops activates the \lisp{}NoObjectForMsg\rm{}{\send1{(USINGLOOPS.IM;7 32918 \count0)}} method in the kernel class \lisp{}Object\rm{}. 

The response to this condition can be changed as described below.

This condition can arise if the filler refers to an object that is not in the current environment.  For example,



\lisp{}{\nofill{}({\char'137} ({\char'44} FOO) \arg{}selector\lisp{} \arg{}arg\sub{1}\lisp{} $\cdots$ \arg{}arg\sub{N}\lisp{})\par}\rm{}



will cause the condition if there is no class named \lisp{}FOO\rm{} in the current environment.  In the default case, this causes an error.  A user can return from the error by typing



\lisp{}{\nofill{}RETURN \arg{}MyValue\lisp{}\par}\rm{}



to let the process continue, returning \arg{}MyValue\rm{} as the value that should have been returned had the method been applied successfully.

Alternatively it is possible to create user-specific responses to this condition by creating a class with a \lisp{}NoObjectForMsg\rm{}{\send1{(USINGLOOPS.IM;7 33742 \count0)}} method and setting the global LISP variable \lisp{}DefaultObject\rm{}{\send1{(USINGLOOPS.IM;7 33831 \count0)}} to that class.  The arguments to the \lisp{}NoObjectForMsg\rm{} method are \arg{}object\rm{} and \arg{}Selector\rm{}.  This method should carry out whatever response is appropriate, apply the method that was intended, and return the value of that application.    









\vskip10pt

\bf{}\noindent\save0\hbox{13.6.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}When the Selector is Not Recognized

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 34233 \count0)}}\penalty 2000
\mark{When the Selector is Not Recognized}
\penalty 2000
\vskip10pt
\penalty 2000
If the object is recognized but the selector is not, then the object is sent a \lisp{}MessageNotUnderstood\rm{}{\send1{(USINGLOOPS.IM;7 34379 \count0)}} message as follows:



\lisp{}{\nofill{}({\char'137} \arg{}object\lisp{} MessageNotUnderstood \arg{}selector\lisp{})\par}\rm{}



In most cases, this invokes the default method on the kernel class \lisp{}Object\rm{} which attempts to perform spelling correction.  If the correction fails, then a break is caused.  If the user then types



\lisp{}{\nofill{}RETURN \arg{}selector\lisp{}\par}\rm{}



to the Lisp Break Package, the selector so named will be used.

Alternatively it is possible to create user-specific responses to this condition by providing a \lisp{}MessageNotUnderstood\rm{} method in some super of the object.  This method should return a Lisp atom other than \lisp{}NIL\rm{}, which is then used as the selector as the \lisp{}SEND\rm{} is tried again.  













\vskip10pt

\bf{}\noindent\save0\hbox{13.7}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Breaking and Tracing Methods

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 35286 \count0)}}\penalty 2000
\mark{Breaking and Tracing Methods}
\penalty 2000
\vskip10pt
\penalty 2000






\vskip 10pt
{\send1{(USINGLOOPS.IM;7 35345 \count0)}}\formatdef{462pt}{\lisp{}(BreakMethod \arg{}className selector\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent This function will break the method called by \arg{}selector\rm{} in the specified class.  It will find the function name and break it, even if the selector is only found in a superclass.  All calls to that function will be broken, even ones that do not come from className.


\parshape 1    0
pt  462pt {}







\vskip 10pt
{\send1{(USINGLOOPS.IM;7 35677 \count0)}}\formatdef{462pt}{\lisp{}(TraceMethod \arg{}className selector\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Similar to \lisp{}BreakMethod\rm{}, except that it traces the appropriate method.


\parshape 1    0pt  462pt {}


The Lisp function \lisp{}UNBREAK\rm{} will unbreak the function which was broken.









\vskip10pt

\bf{}\noindent\save0\hbox{13.8}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Monitoring Variable Access

\rm{}\penalty 2000
{\send1{(USINGLOOPS.IM;7 35962 \count0)}}\penalty 2000
\mark{Monitoring Variable Access}
\penalty 2000
\vskip10pt
\penalty 2000






\vskip 10pt
{\send1{(USINGLOOPS.IM;7 36044 \count0)}}\formatdef{462pt}{\lisp{}(BreakIt \arg{}self varName propName type breakOnGetAlsoFlg\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent This function is used for causing an Interlisp break when the value of a variable or property is set or fetched.  The \arg{}type\rm{} argument is one of \lisp{}IV\rm{}, \lisp{}CV\rm{}, \lisp{}METHOD\rm{}, or \lisp{}CLASS\rm{} for instance variables, class variables, method properties, or class properties respectively.  If it is \lisp{}NIL\rm{}, then \lisp{}IV\rm{} is assumed.  If \arg{}propName\rm{} is \lisp{}NIL\rm{}, then type must be \lisp{}IV\rm{} or \lisp{}CV\rm{} and \lisp{}BreakIt\rm{} refers to the value of a variable.

If \arg{}breakOnGetAlsoFLg\rm{} is \lisp{}NIL\rm{} then the break is only entered when an attempt is made to store into the value.  If \arg{}breakOnGetAlsoFLg\rm{} is \lisp{}T\rm{}, then breaks will also occur on attempts to fetch the value.  



\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(USINGLOOPS.IM;7 36825 \count0)}}\formatdef{462pt}{\lisp{}(TraceIt \arg{}self varName propName type traceOnGetAlsoFlg\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Similar to \lisp{}BreakIt\rm{}, except that it will trace the value of a variable or property, printing the old and new values when the variable or property is accessed.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(USINGLOOPS.IM;7 37057 \count0)}}\formatdef{462pt}{\lisp{}(UnBreakIt \arg{}self varName propName type\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent This function is used to remove monitoring (breaking or tracing) for the specified variable or property.  If \arg{}self\rm{}=\lisp{}NIL\rm{}, then all known breaks and traces are removed.


\parshape 1    0pt  462pt {}


















\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{14}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}THE LOOPS KERNEL

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 64 \count0)}}\penalty 2000
\mark{THE LOOPS KERNEL}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(KERNAL.IM;3 83 \count0)}}




\vskip10pt

\bf{}\noindent\save0\hbox{14.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Golden Braid (Object, Class, MetaClass)

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 202 \count0)}}\penalty 2000
\mark{The Golden Braid (Object, Class, MetaClass)}
\penalty 2000
\vskip10pt
\penalty 2000
All objects are directly or indirectly a subclass of the object called \lisp{}Object\rm{}.{\send1{(KERNAL.IM;3 311 \count0)}}  \lisp{}Object\rm{} holds all the methods for the defualt behavior of objects.   Heuristics for using these classes.  This is the only object with no super classes.

\lisp{}Class\rm{}{\send1{(KERNAL.IM;3 519 \count0)}} is the class which holds the default behavior for all classes as objects.  \lisp{}Class\rm{} is the default MetaClass for all classes.  If \lisp{}Class\rm{} is not the MetaClass for a class, it must be on the supers of that metaClass.  There are messages fielded by \lisp{}Class\rm{} that know how to create and initialize instances.

\lisp{}MetaClass\rm{}{\send1{(KERNAL.IM;3 885 \count0)}} is the class which holds the default behavior for classes which create classes.  \lisp{}MetaClass\rm{} is the metaclass for \lisp{}Class\rm{}, and is the only class which is its own metaClass. In accordance with the paragraph above \lisp{}Class\rm{} is a super of \lisp{}MetaClass\rm{}.  













\vskip10pt

\bf{}\noindent\save0\hbox{14.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Perspectives and Nodes

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 1518 \count0)}}\penalty 2000
\mark{Perspectives and Nodes}
\penalty 2000
\vskip10pt
\penalty 2000
In many cases it is useful to organize information in terms of multiple points of view.  For example, information about a man might be organized in terms of his role as a father, as an employee, and as a traveler.  Each point of view, called a perspective, contains information for a different purpose.  The perspecitives are related to each other in the sense that they collectively provide information about the same object.  Loops supports this organizational metaphor by providing special mixin classes called \lisp{}Perspective\rm{} and \lisp{}Node\rm{}.




\vskip 10pt
{\send1{(KERNAL.IM;3 2116 \count0)}}\formatdef{462pt}{\lisp{}Perspective\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}

IVs:



\vskip 10pt
{\send1{(KERNAL.IM;3 2187 \count0)}}\formatdef{462pt}{\lisp{}perspectiveNode\rm{}}{IV of Perspective}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Indirect pointer to onode containing all perspectives of this object.


\parshape 1    0pt  462pt {}

Methods:



\vskip 10pt
{\send1{(KERNAL.IM;3 2424 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} AddPersp \arg{}viewName\lisp{} \arg{}view\lisp{})\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Adds a perspective to my node.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 2587 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DeleteMeAsPersp)\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Delete this object as a perspective of node.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 2832 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DeletePersp \arg{}viewName\lisp{} \arg{}view\lisp{} \arg{}dontCauseError\lisp{})\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Deletes a perspective from node.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 2981 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy)\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Destroy self but leave other perspectives on Node.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 3150 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy!)\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Destroy self, Node and all other perspectives on Node.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 3377 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} GetPersp \arg{}perspName\lisp{} \arg{}causeError\lisp{})\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the perspective of this instance with viewName perspName.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 3611 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} MakePersp \arg{}viewName\lisp{} \arg{}nodeType\lisp{})\lisp{}\rm{}}{Method of Perspective}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent If no current perspectiveNode exists, then a node will be created of class \arg{}nodeType\rm{} (or \lisp{}Node\rm{} if \arg{}nodeType\rm{}=\lisp{}NIL\rm{}).  \arg{}nodeType\rm{} should be a subclass of \lisp{}Node\rm{}.  \arg{}self\rm{} will be made the value of the property \arg{}viewName\rm{} on \lisp{}IV\rm{} perspectives of node.  If \arg{}self\rm{} already has a node, then it is used.


\parshape 1    0pt  462pt {}





\vskip 10pt
{\send1{(KERNAL.IM;3 3998 \count0)}}\formatdef{462pt}{\lisp{}Node\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0
pt  462pt {}

IVs:



\vskip 10pt
{\send1{(KERNAL.IM;3 4059 \count0)}}\formatdef{462pt}{\lisp{}perspectives\rm{}}{IV of Node}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Associated objects are stored on the property list of \lisp{}perspectives\rm{} under their perspective names.  The value of this IV is irrelevant.


\parshape 1    0pt  462pt {}

Methods:




\vskip 10pt
{\send1{(KERNAL.IM;3 4398 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} AddPersp \arg{}viewName\lisp{} \arg{}view\lisp{} \arg{}dontCauseError\lisp{})\lisp{}\rm{}}{Method of Node}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Adds a perspective to a node on the IV \lisp{}perspectives\rm{} as value of property \arg{}viewName\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 4687 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DeletePersp \arg{}viewName\lisp{} \arg{}view\lisp{} \arg{}dontCauseError\lisp{})\lisp{}\rm{}}{Method of Node}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Deletes a perspective of a node on the IV \lisp{}perspectives\rm{} on property \arg{}viewName\rm{}.  Checks for consistency.  Removes from IV \lisp{}pespectiveNode\rm{} of \arg{}view\rm{}, \arg{}self\rm{} as value, and \arg{}viewName\rm{} from property \lisp{}myViewName\rm{}.  If \arg{}view\rm{} is not that perspective, then causes an error, unless surpressed.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 5119 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy)\lisp{}\rm{}}{Method of Node}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Destroy the node after detaching all its perspectives.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 5285 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy!)\lisp{}\rm{}}{Method of Node}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Destroy the node and all its perspectives.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 5493 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} GetPersp \arg{}perspName\lisp{} \arg{}causeError\lisp{})\lisp{}\rm{}}{Method of Node}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Returns the perspective of this node with viewName of \arg{}perspName\rm{}.


\parshape 1    0pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{14.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Useful Mixins

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 5666 \count0)}}\penalty 2000
\mark{Useful Mixins}
\penalty 2000
\vskip10pt
\penalty 2000
\lisp{}NamedObject\rm{} and \lisp{}GlobalNamedObject\rm{} contain only one instance variable, \lisp{}name\rm{}{\send1{(KERNAL.IM;3 5797 \count0)}}{\send1{(KERNAL.IM;3 5835 \count0)}} which holds the name of this object.  Any Loops object can be named, but \lisp{}NamedObject\rm{} and \lisp{}GlobalNamedObject\rm{} both have their names as part of their structure, and if the structure is changed they update their name.  As indicated by its name, instances of \lisp{}GlobalNamedObject\rm{} are named in the global name table and will be known independent of the environment they are in.  Instances of \lisp{}NamedObject\rm{} may only be known in a single environment, and the name may be reused in another environment.



\vskip 10pt
{\send1{(KERNAL.IM;3 6397 \count0)}}\formatdef{462pt}{\lisp{}NamedObject\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 6453 \count0)}}\formatdef{462pt}{\lisp{}GlobalNamedObject\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent 

\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 6503 \count0)}}\formatdef{462pt}{\lisp{}DatedObject\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}DatedObject\rm{} has appropriate initial active values on its two instance variables so that they are filled in at creation with the right values.



\parshape 1    0pt  462pt {}


IVs:



\vskip 10pt
{\send1{(KERNAL.IM;3 6716 \count0)}}\formatdef{462pt}{\lisp{}created\rm{}}{IV of DatedObject}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Date and time of creation of object.


\parshape 1    0pt  462pt {}



\vskip 10pt
{\send1{(KERNAL.IM;3 6810 \count0)}}\formatdef{462pt}{\lisp{}creator\rm{}}{IV of DatedObject}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent USERNAME of creator of object.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 6889 \count0)}}\formatdef{462pt}{\lisp{}Varlength\rm{}}{Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}VarLength\rm{} is a mixin class which allows a class to have indexed instance variables, from 1 to \lisp{}({\char'137} \arg{}obj\lisp{} Length)\rm{}.  These have not yet been extensively used.


\parshape 1    0pt  462pt {}

IVs:



\vskip 10pt
{\send1{(KERNAL.IM;3 7127 \count0)}}\formatdef{462pt}{\lisp{}indexedVars\rm{}}{IV of Varlength}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Place where indexed variables are stored for \lisp{}VarLength\rm{} classes.


\parshape 1    0pt  462pt {}

Methods:



\vskip 10pt
{\send1{(KERNAL.IM;3 7319 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Length)\lisp{}\rm{}}{Method of Varlength}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns number of indexed variables allocated in this instance.


\parshape 1    0
pt  462pt {}













\vskip10pt

\bf{}\noindent\save0\hbox{14.4}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The MetaClass Named {\lquotes}Class{\rquotes}

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 7550 \count0)}}\penalty 2000
\mark{The MetaClass Named {\lquotes}Class{\rquotes}}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(KERNAL.IM;3 7587 \count0)}}

This sections describes the methods defined in the metaClass \lisp{}Class\rm{}.  Any of these methods can be augmented or superceeded in a particular class.  The complete list of methods associated with a class can be determined by using the browser.


The \lisp{}Add\rm{}, \lisp{}Delete\rm{}, \lisp{}List\rm{} and \lisp{}List!\rm{} methods have an argument \arg{}type\rm{} which specifies the type of element to be added, deleted, or listed.  For specifying single items, \arg{}type\rm{} should be one of \lisp{}IV\rm{}, \lisp{}CV\rm{}, \lisp{}IVProp\rm{}, \lisp{}CVProp\rm{}, \lisp{}Method\rm{}, \lisp{}Super\rm{}, or \lisp{}Meta\rm{}.  For specifying sets of items, \arg{}type\rm{} should be \lisp{}IVs\rm{}, \lisp{}CVs\rm{}, \lisp{}IVProps\rm{}, \lisp{}CVProps\rm{}, \lisp{}Methods\rm{}, \lisp{}Supers\rm{}, \lisp{}Selectors\rm{}, or \lisp{}Functions\rm{}.


In the following methods, adding or deleting instance variables and instance variable properties affects the class, and and therefore affects only instances created after the change.  Already existing instances are not changed. 






\vskip 10pt
{\send1{(KERNAL.IM;3 8942 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Add \arg{}type\lisp{} \arg{}name\lisp{} \arg{}value\lisp{} \arg{}propertyName\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Add an instance specified by \arg{}type\rm{} to the class.  E.g. if \arg{}type\rm{}=\lisp{}IV\rm{} then add an instance variable with the given name using the given value as default.  If \arg{}propertyName\rm{} is given, use \arg{}value\rm{} instead as the property value on \arg{}type\rm{} created or found.  The type must be one of the item types specified above: \lisp{}IV\rm{}, \lisp{}CV\rm{}, \lisp{}IVProp\rm{}, \lisp{}CVProp\rm{}, \lisp{}Method\rm{}, \lisp{}Super\rm{}, or \lisp{}Meta\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 9499 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} CommentMethods)\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent For each method in the class, obtain its argument list, and insert this in the class definition under the method property \lisp{}args\rm{}.{\send1{(KERNAL.IM;3 9664 \count0)}}  If the source code of a method is in core, extract the comment which should be the fourth item in the source code, and insert in the class definition under the method property \lisp{}doc\rm{}.{\send1{(KERNAL.IM;3 9882 \count0)}}  If no comment is found in the source code, put the user into the editor looking at that function.  When editing is finished, retrieve the comment from the method.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 10244 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} CopyMethod \arg{}mySelector\lisp{} \arg{}newClass\lisp{} \arg{}newSelector\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Copy the method associated with the selector \arg{}mySelector\rm{} from \arg{}self\rm{} to \arg{}newClass\rm{} (under the new selector \arg{}newSelector\rm{}).  \arg{}newSelector\rm{} defaults to \arg{}mySelector\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 10601 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DefMethod \arg{}selector\lisp{} \arg{}args\lisp{} \arg{}exp\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Adds a method for \arg{}selector\rm{} to class.  If \arg{}args\rm{} and \arg{}expr\rm{} are \lisp{}NIL\rm{}, puts the user into the editor)


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 10877 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Delete \arg{}type\lisp{} \arg{}name\lisp{} \arg{}prop\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Deletes the specified element from class.  \arg{}type\rm{} must be one of \lisp{}IV\rm{}, \lisp{}CV\rm{}, \lisp{}IVProp\rm{}, \lisp{}CVProp\rm{}, \lisp{}Method\rm{}, \lisp{}Super\rm{}, or \lisp{}Meta\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 11153 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy)\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Destroys (deletes) a class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 11293 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy!)\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Recursive version of Destroy. Destroys class and its subclasses.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 11486 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Edit \arg{}commands\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Calls the Interlisp Editor on the source for class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 11702 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} EditMethod \arg{}selector\lisp{} \arg{}commands\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Finds the function associated with \arg{}selector\rm{} in class, and calls the Interlisp Editor on it.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 11942 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} FetchMethod \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the name of the function which implements this method in this class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 12161 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} HasCV \arg{}CVName\lisp{} \arg{}prop\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Tests if class has the specified class variable{\char'57}property.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 12361 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} HasIV \arg{}IVName\lisp{} \arg{}prop\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Tests if class has the specified instance variable{\char'57}property.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 12618 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} List \arg{}componentType\lisp{} \arg{}componentName\lisp{} \arg{}propName\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent List the immediate components of a class.  \arg{}componentType\rm{} is one of the item or set specifiers described above.  If \arg{}componentType\rm{} is one of the item specifiers, then \arg{}componentName\rm{} should be specified;  \lisp{}List\rm{} will show that item.  If \arg{}componentType\rm{} is \lisp{}IVProps\rm{} or \lisp{}CVProps\rm{}, then \lisp{}List\rm{} will show just the property names of the named item.  Otherwise, for all set descriptors, it will list all relevant items.  \arg{}propName\rm{} must be specified only if component is \lisp{}IVProps\rm{} or \lisp{}CVProps\rm{}.  \lisp{}Selectors\rm{} and \lisp{}Methods\rm{} are synonyms, returning the list of selectors for the class; \lisp{}Functions\rm{} returns the list of names of functions called for methods in this class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 13515 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} List! \arg{}type\lisp{} \arg{}name\lisp{} \arg{}verboseFlg\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Recursive version of \lisp{}List\rm{}.  Omits things inherited from \lisp{}Object\rm{} and \lisp{}Class\rm{} unless \arg{}verboseFlg\rm{}=\lisp{}T\rm{}.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 13781 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} MethodDoc \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Print documentation for the method associated with \arg{}selector\rm{} in TTY window.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 14026 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} MoveMethod \arg{}newClass\lisp{} \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Moves the method specified by \arg{}selector\rm{} from this class to the specified class, changing the name of the function if it is of form \lisp{}\arg{}className\lisp{}.\arg{}selector\lisp{}\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 14339 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} New \arg{}name\lisp{} \arg{}supers\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \lisp{}New\rm{} method for \lisp{}MetaClass\rm{}.  Since \lisp{}MetaClass\rm{} is its own metaClass, this needs to work correctly whether \arg{}self\rm{} is \lisp{}Class\rm{} or \lisp{}MetaClass\rm{} or a subClass of \lisp{}MetaClass\rm{}.  Work is done by \lisp{}DefineClass\rm{}{\send1{(KERNAL.IM;3 14600 \count0)}} in LOOPS.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 14768 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} NewTemp \arg{}selector\lisp{} \arg{}superFlg\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Make a new temporary instance of this class which will not get saved on a database unless referred to by another saved object.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 15019 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} OnFile \arg{}file\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns \lisp{}T\rm{} if \arg{}self\rm{} is defined on the file \arg{}file\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 15201 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PP \arg{}file\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Prettyprints the class on the file \arg{}file\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 15366 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PP! \arg{}file\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent PrettyPrints the class at all levels.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 15530 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PPM \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Prettyprints the function which implements \arg{}selector\rm{} in this class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 15739 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PPMethod \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Prettyprints the function which implements \arg{}selector\rm{} in this class.





\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 16012 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Put \arg{}type\lisp{} \arg{}name\lisp{} \arg{}value\lisp{} \arg{}prop\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent \arg{}type\rm{} must be one of \lisp{}IV\rm{}, \lisp{}CV\rm{}, \lisp{}IVProp\rm{}, \lisp{}CVProp\rm{}, \lisp{}Method\rm{}, \lisp{}Super\rm{}, or \lisp{}Meta\rm{}.  Adds the specified type to the class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 16334 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Rename \arg{}newName\lisp{} \arg{}environment\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Give a class a new name, renaming those methods of the form \lisp{}\arg{}className\lisp{}.\arg{}selector\lisp{}\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 16575 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} ReplaceSupers \arg{}supers\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Replace the entire supers list for this class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 16784 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} SetName \arg{}newName\lisp{} \arg{}environment\lisp{})\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Change the name of the class, forgetting old name.  Change the names of all methods which are of the form \lisp{}\arg{}className\lisp{}.\arg{}selector\lisp{}\rm{}.  Same as \lisp{}Rename\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 17069 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} SubClasses)\lisp{}\rm{}}{Method of Class}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns a list of immediate subclasses currently known for this class.


\parshape 1    0
pt  462pt {}










\vskip10pt

\bf{}\noindent\save0\hbox{14.5}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}The Class Named {\lquotes}Object{\rquotes}

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 17269 \count0)}}\penalty 2000
\mark{The Class Named {\lquotes}Object{\rquotes}}
\penalty 2000
\vskip10pt
\penalty 2000
{\send1{(KERNAL.IM;3 17303 \count0)}}

All classes have \lisp{}Object\rm{} as one of their supers, directly or indirectly.  Therefore, all instances know how to respond to the messages defined in \lisp{}Object\rm{}.  These can of course be overridden in any class, but \lisp{}Object\rm{} provides a set of default behaviors, and generally available subroutines.  





\vskip 10pt
{\send1{(KERNAL.IM;3 17769 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} AddIV \arg{}name\lisp{} \arg{}value\lisp{} \arg{}prop\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Adds an IV to instance.  If it is not in regular set, puts it in assoc List on otherIVs.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 17995 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} AssocKB \arg{}newKBName\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Change assocKB of this object to \arg{}newKBName\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 18202 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} At \arg{}varName\lisp{} \arg{}prop\lisp{} \arg{}index\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the value of an {\lquotes}instance variable{\rquotes} for an object.  For an instance object, instance variables hold local state.  For an object that is a class, we use {\lquotes}instance variable{\rquotes} to refer to the variables that are private to instances of the class.  If the value is an active value, \lisp{}GetValue\rm{} activates its \arg{}getFn\rm{}. 


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 18747 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} BreakIt \arg{}varName\lisp{} \arg{}propName\lisp{} \arg{}type\lisp{} \arg{}brkOnGetAlsoFlg\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Creates an active value which will cause a break when this value is changed.  If \arg{}brkOnGetAlsoFlg\rm{}=\lisp{}T\rm{}, this will also break when the value is fetched.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 19015 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Class)\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns the class of this object.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 19164 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} ClassName)\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Returns the className of the class of the object.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 19341 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} CopyDeep \arg{}KBC\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Copies the unit, sharing the iName list, copying instances, activeValues and lists. 


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 19553 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} CopyShallow)\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Makes a new instance (a copy of this instance, not copying the values of the instance variables), with the same contents as \arg{}self\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 19856 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DeleteIV \arg{}varName\lisp{} \arg{}propName\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Removes an IV from an instance.  No longer shares IVName List with class.  Some programs which depend on IV may not work.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 20139 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DeleteIVProp \arg{}ivName\lisp{} \arg{}ivProp\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Deletes a property of an instance variable.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 20294 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Destroy)\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Destroy an object in an environment.  Removes all IVs, class pointers, etc.  For garbage collection by user.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 20840 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} DoMethod \arg{}selector\lisp{} \arg{}class\lisp{} \arg{}arg\sub{1}\lisp{} \arg{}arg\sub{2}\lisp{} \arg{}arg\sub{3}\lisp{} \arg{}arg\sub{4}\lisp{} \arg{}arg\sub{5}\lisp{} \arg{}arg\sub{6}\lisp{} \arg{}arg\sub{7}\lisp{} \arg{}arg\sub{8}\lisp{} \arg{}arg\sub{9}\lisp{} \arg{}arg\sub{10}\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Message form of the function \lisp{}DoMethod\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 21013 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Edit \arg{}commands\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Calls the Interlisp editor on the source of the object.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 21212 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} HasIV \arg{}ivName\lisp{} \arg{}prop\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns \lisp{}T\rm{} if \arg{}self\rm{} contains the specified IV.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 21401 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Inspect \arg{}ASTYPE\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Calls the Interlisp inspector to examine \arg{}self\rm{} (as an object of type \arg{}ASTYPE\rm{}).


\parshape 1    0pt  462pt {}






\vskip 10pt
{\send1{(KERNAL.IM;3 21684 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} InstOf \arg{}className\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns \lisp{}T\rm{} if \arg{}self\rm{} is an immediate instance of the class with name \arg{}className\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 21917 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} InstOf! \arg{}className\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Returns \lisp{}T\rm{} if \arg{}self\rm{} is an instance of the class with name \arg{}className\rm{} either directly or through the supers chain of its class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 22197 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} IVMissing \arg{}varName\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Called from macro FetchIVDescr when there is no IV \arg{}varName\rm{}.  If \arg{}varName\rm{} is an IV of the class, then it adds IV to the instance and returns the IVDescr as requested.  Will also do this if user returns with \lisp{}OK\rm{} from \lisp{}HELPCHECK\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 22574 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} List \arg{}typeName\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent List IV properties, IVS of object, or other properties inherited from class.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 22818 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} List! \arg{}type\lisp{} \arg{}name\lisp{} \arg{}verboseFlg\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Recursive form of \lisp{}List\rm{} for objects.  Omits things inherited from \lisp{}Object\rm{} unless \arg{}verboseFlg\rm{} is \lisp{}T\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 23126 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} MessageNotUnderstood \arg{}selector\lisp{} \arg{}superFlg\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Invoked when a selector is not found for an object during a message sending operation.  Attempts to do spelling correction on the selector.  Causes an error if this fails.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 23447 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} NoObjectForMsg \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Called from \lisp{}FetchMethodOrHelp\rm{}{\send1{(KERNAL.IM;3 23510 \count0)}} when \arg{}self\rm{} is not a Loops object with a defined class.  A specialized response to this can be tailored in a given Loops application by first reseting the global Interlisp variable \lisp{}DefaultObject\rm{}{\send1{(KERNAL.IM;3 23740 \count0)}} to point to an object.  This default object will field \lisp{}NoObjectForMsg\rm{} messages from \lisp{}FetchMethodOrHelp\rm{}.  The method for \lisp{}NoObjectForMsg\rm{} on \lisp{}DefaultObject\rm{} should return a default value, usually dependent on the selector.  

This version of \lisp{}NoObjectForMsg\rm{} just causes an error break.  A user can return from the error by typing \lisp{}RETURN \arg{}value\lisp{}\rm{}, where \arg{}value\rm{} is the value that should have been returned as the result of sending \arg{}selector\rm{} to \arg{}self\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 24345 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PP)\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent PrettyPrints an instance definition on \arg{}file\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 24515 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PP! \arg{}file\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent PrettyPrints an instance to all levels.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 24682 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} PrintOn \arg{}file\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent This is the default printing function for \lisp{}Object\rm{}.  It distinguishes between temporary objects, named objects, and others.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 25002 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Put \arg{}varName\lisp{} \arg{}newValue\lisp{} \arg{}propName\lisp{} \arg{}index\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Puts \arg{}newValue\rm{} in an instance variable (see \lisp{}GetValue\rm{}, page X.XX).  If the value{\char'57}property of the variable contains an active value, the \arg{}putFn\rm{} is activated.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 25346 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Rename \arg{}newName\lisp{} \arg{}environment\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Removes an old name, and gives it new name.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 25575 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} SetName \arg{}name\lisp{} \arg{}environment\lisp{} \arg{}noBitchFlg\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Associates a name with an object in an environment.  This works for instances and classes.  An object can have more than one name.


\parshape 1    0
pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 25917 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} TraceIt \arg{}varName\lisp{} \arg{}propName\lisp{} \arg{}type\lisp{} \arg{}traceGetAlsoFlg\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Creates an active value which will cause tracing when this variable is changed.  Will also trace on fetches if \arg{}traceGetAlsoFlg\rm{}=\lisp{}T\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 26221 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} UnSetName \arg{}name\lisp{} \arg{}environment\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent If \arg{}name\rm{} actually names \arg{}self\rm{} in \arg{}environment\rm{}, then delete the association between \arg{}self\rm{} and \arg{}name\rm{}.



\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 26489 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} Understands \arg{}selector\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Tests if \arg{}self\rm{} will respond to \arg{}selector\rm{}.


\parshape 1    0pt  462pt {}




\vskip 10pt
{\send1{(KERNAL.IM;3 26708 \count0)}}\formatdef{462pt}{\lisp{}\lisp{}({\char'137} \arg{}self\lisp{} WhereIs \arg{}name\lisp{} \arg{}type\lisp{} \arg{}propName\lisp{})\lisp{}\rm{}}{Method of Object}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Searches the supers hierarchy until it finds the class from which \arg{}type\rm{} is inherited.  \arg{}type\rm{}=\lisp{}NIL\rm{} defaults to \lisp{}METHODS\rm{}.


\parshape 1    0pt  462pt {}











\vskip10pt

\bf{}\noindent\save0\hbox{14.6}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Functions for changing Loops Structure

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 27005 \count0)}}\penalty 2000
\mark{Functions for changing Loops Structure}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip10pt

\bf{}\noindent\save0\hbox{14.6.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Moving and Renaming Methods

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 27093 \count0)}}\penalty 2000
\mark{Moving and Renaming Methods}
\penalty 2000
\vskip10pt
\penalty 2000
There are a number of Interlisp functions available to help in the process of reorganizing class structures.  It is often the case in the development of a set of classes for some job that one finds some common super class of a set of classes, and wants to move a method up to the super, or copy it down from the super.  Also renaming both the selector and the function of a method is sometimes useful.







\vskip 10pt
{\send1{(KERNAL.IM;3 27571 \count0)}}\formatdef{462pt}{\lisp{}(RenameMethod \arg{}className oldSelector newSelector\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Changes the selector \arg{}oldSelector\rm{} to \arg{}newSelector\rm{} in \arg{}className\rm{} and if the function name is \lisp{}\arg{}className\lisp{}.\arg{}oldSelector\lisp{}\rm{} does a \lisp{}RENAME\rm{} to \lisp{}\arg{}className\lisp{}.\arg{}newSelector\lisp{}\rm{}.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(KERNAL.IM;3 27860 \count0)}}\formatdef{462pt}{\lisp{}(RenameMethodFunction \arg{}class oldName newName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000


\parshape 1   92pt  370pt {}
\noindent Renames a function used as a method in \arg{}class\rm{}.  Does not change the selector.  Complains if \arg{}oldName\rm{} is not found.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(KERNAL.IM;3 28063 \count0)}}\formatdef{462pt}{\lisp{}(MoveMethod \arg{}oldClassname newClassName selector\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Moves the method from \arg{}oldClassname\rm{} to \arg{}newClassName\rm{}, and renames the function if it is of the form \lisp{}\arg{}oldClassname\lisp{}.\arg{}selector\lisp{}\rm{} to \lisp{}\arg{}newClassName\lisp{}.\arg{}selector\lisp{}\rm{}.


\parshape 1    0
pt  462pt {}








\vskip 10pt
{\send1{(KERNAL.IM;3 28320 \count0)}}\formatdef{462pt}{\lisp{}(CalledFns \arg{}classes definedFlg\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Given a list of classes, this function computes the list of all functions called by those classes.  If \arg{}definedFlg\rm{}=\lisp{}T\rm{}, only returns the list of those functions which are defined.


\parshape 1    0pt  462pt {}








\vskip10pt

\bf{}\noindent\save0\hbox{14.6.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Moving and Renaming Variables

\rm{}\penalty 2000
{\send1{(KERNAL.IM;3 28647 \count0)}}\penalty 2000
\mark{Moving and Renaming Variables}
\penalty 2000
\vskip10pt
\penalty 2000
It is sometimes convenient to be able to move methods and variables when reconfiguring classes in an inheritance lattice.  The following functions are provided for this.:








\vskip 10pt
{\send1{(KERNAL.IM;3 28904 \count0)}}\formatdef{462pt}{\lisp{}(RenameVariable \arg{}className oldVarName newVarName classFlg\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Changes the name of the variable from \arg{}oldVarName\rm{} to \arg{}newVarName\rm{}.  Changes any references to these variables in methods of the class. 



\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(KERNAL.IM;3 29133 \count0)}}\formatdef{462pt}{\lisp{}(MoveVariable \arg{}oldClassName newClassname variableName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92pt  370pt {}
\noindent Moves the entire description of an instance variable into the new class.


\parshape 1    0pt  462pt {}








\vskip 10pt
{\send1{(KERNAL.IM;3 29295 \count0)}}\formatdef{462pt}{\lisp{}(MoveClassVariable \arg{}oldClassName newClassname variableName\lisp{})\arg{}\lisp{}\rm{}}{Function}

\penalty 2000\vskip-10pt\penalty 2000

\parshape 1   92
pt  370pt {}
\noindent Moves the entire description of a class variable into the new class.


\parshape 1    0pt  462pt {}



























\vfill\eject\def\noheaderonce{T}

\bf{}\noindent\save0\hbox{15}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}LOOPS AND THE INTERLISP SYSTEM

\rm{}\penalty 2000
{\send1{(LOOPSANDINTERLISP.IM;1 93 \count0)}}\penalty 2000
\mark{LOOPS AND THE INTERLISP SYSTEM}
\penalty 2000
\vskip10pt
\penalty 2000


\vskip10pt

\bf{}\noindent\save0\hbox{15.1}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Saving Class and Instance Definitions on Files

\rm{}\penalty 2000
{\send1{(LOOPSANDINTERLISP.IM;1 218 \count0)}}\penalty 2000
\mark{Saving Class and Instance Definitions on Files}
\penalty 2000
\vskip10pt
\penalty 2000
Loops has been integrated with the Interlisp file system to allow saving of class definitions on files.  The file command:



\lisp{}{\nofill{}(CLASSES * \arg{}classNameList\lisp{})\par}\rm{}

{\send1{(LOOPSANDINTERLISP.IM;1 409 \count0)}}

added to the filecoms of any file will allow one to dump out the prettyprinted version of the source you see when you edit the class definition.  These class names can be listed in any order in a single list, provided that all super classes of a class on the list are on the list as well, or will be previously defined.  



\lisp{}{\nofill{}(INSTANCES * \arg{}instanceNameList\lisp{})\par}\rm{}

{\send1{(LOOPSANDINTERLISP.IM;1 806 \count0)}}

added to the filecoms of any file will allow one to dump out the prettyprinted versions of named instances, as well as any unnamed instances that they point to.

Functions used to implement methods are ordinary Interlisp functions.  Those that are named automatically by Loops as \lisp{}\arg{}className\lisp{}.\arg{}selector\lisp{}\rm{} start with the same characters; they will be found alphabetically together on any function list which is created.  The function \lisp{}CalledFns\rm{} (page X.XX) can be used get a list of all functions used by a list of classes.








\vskip10pt

\bf{}\noindent\save0\hbox{15.2}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Classes for Lisp Datatypes

\rm{}\penalty 2000
{\send1{(LOOPSANDINTERLISP.IM;1 1507 \count0)}}\penalty 2000
\mark{Classes for Lisp Datatypes}
\penalty 2000
\vskip10pt
\penalty 2000


One can use the message sending protocol with records (lists) whose first element is a class, or ordinary Interlisp datatypes.  In the first case, the first element is used as the class to look up the method to be used.  In the second case, the class is found using the function \lisp{}(GetLispClass \arg{}obj\lisp{})\rm{},{\send1{(LOOPSANDINTERLISP.IM;1 1915 \count0)}} which looks it up in the hash table \lisp{}LispClassTable\rm{},{\send1{(LOOPSANDINTERLISP.IM;1 1999 \count0)}} based on the type name of the datatype.

We call datatypes with associated classes and records with first element a class \sl{}pseudoclasses\rm{},{\send1{(LOOPSANDINTERLISP.IM;1 2162 \count0)}} and instances of them \sl{}pseudoinstances\rm{}.{\send1{(LOOPSANDINTERLISP.IM;1 2229 \count0)}}  If \lisp{}GetValue\rm{} or \lisp{}PutValue\rm{} are called with \arg{}self\rm{} bound to a pseudoinstance, then the method associated with the selector \lisp{}GetValue\rm{} in the pseudoclass (call it \lisp{}PC\rm{}) is called as follows:



\lisp{}{\nofill{}(APPLY* (GetMethod PC 'GetValue) \arg{}instance\lisp{} \arg{}varName\lisp{} \arg{}propName\lisp{})\par}\rm{}



or



\lisp{}{\nofill{}(APPLY* (GetMethod PC 'PutValue) \arg{}instance\lisp{} \arg{}varName\lisp{} \arg{}newValue\lisp{} \arg{}propName\lisp{})\par}\rm{}



If the associated class \lisp{}PC\rm{} has a \lisp{}GetValue\rm{} (\lisp{}PutValue\rm{}) method, then values of the variables can be found.  This allows a mixture of compiled access to datatype fields, and interpreted access within Loops.









\vskip10pt

\bf{}\noindent\save0\hbox{15.3}\ifdimen 1wd0>30pt{\box0\hskip10pt }\else{\hbox to 40pt{\vbox{\box0}\hfill}}Some Details of the Loops implementation

\rm{}\penalty 2000
{\send1{(LOOPSANDINTERLISP.IM;1 3020 \count0)}}\penalty 2000
\mark{Some Details of the Loops implementation}
\penalty 2000
\vskip10pt
\penalty 2000
Methods are implemented by Lisp functions.  The message sending expression:



\lisp{}{\nofill{}({\char'137} \arg{}object\lisp{} \arg{}selector\lisp{} \arg{}arg\sub{1}\lisp{} $\cdots$ \arg{}arg\sub{N}\lisp{})\par}\rm{}



is expanded as a compiler MACRO into 



\lisp{}{\nofill{}(APPLY* (FetchMethodOrHelp \arg{}object\lisp{} '\arg{}selector\lisp{}) \arg{}object\lisp{} \arg{}arg\sub{1}\lisp{} $\cdots$ \arg{}arg\sub{N}\lisp{})\par}\rm{}



{\send1{(LOOPSANDINTERLISP.IM;1 3383 \count0)}}



\lisp{}GetMethod\rm{} returns the name of the Interlisp function associated with \arg{}selector\rm{} anywhere in the class of \arg{}object\rm{}, or in the superClass chain of that class.  Notice that the object is implicitly included as the first argument of the function, as well as being the argument for \lisp{}GetMethod\rm{}.  By syntactic convention the first argument (bound to the object) in any function which is being used as a method is called \lisp{}self\rm{}.  The expression for the object is evaluated only once.

Objects in Loops are represented in memory as Interlisp datatypes.  The datatypes for classes have property lists for methods, class variables, instance variables, and their properties.  Datatypes for instances have property lists for instance variables and their properties.  In general, the selector names and variable names are stored in the class objects.  When instances are read in from a data base, they have their local name tables aligned with the class standards.  Special provisions are provided for handling instances whose variable names do not correspond to current class definitions.  Instances act as if they have local tables for lookup of variables and properties, but they usually share the class name table and no storage is actually allocated for local tables unless it is needed.	

Default values for instance variables and properties are not copied to an instance.  No space for instance variables or properties is allocated until that variable or property has been set individually for the instance.  This means that the default values are not just initial values.  In particular, if a class is altered to change the default value of an instance variable, then all of the instances that do not have individualized values will reflect the new default value.  Also, there is no storage overhead in instances for unchanged properties (e.g., for documentation) defined in classes.  Since individualized values of variables are stored in the instances, there is no need to search the class hierarachy after a variable or property has been set in the instance.  In contrast, since class variables are shared among instances it is always necessary to go to the class (or a super class) to get a value.   

Although many of the ideas of the Loops database were inspired by PIE, the implementation differs along several dimensions.  PIE was intended primarily for use with a browser (i.e., an interactive viewing and editing program), and efficiency was not a primary concern.  Since Loops was intended for use by programs with potentially extensive computational processes, a need for efficient access was perceived and this led to some different tradeoffs in the choice of implementation.

One difference between PIE and Loops is the grainsize of the changes written in layers.  PIE performs separate bookkeeping on changes to values of every variable in objects.  Loops avoids the storage penalty of this by keeping track only of which objects have been changed.  This means that file layers in PIE contain partial objects (e.g., a change to a single variable) while layers in Loops contain complete objects.  In effect, Loops economizes on space (and time) in memory instead of space in the databases.

Another difference is that the Loops implementation tries to reduce the cost of references to values by snapping links to references.  However, link snapping is fundamentally in conflict with a lookup process that takes an environment as an argument.  Link snapping precludes the sharing of objects between environments in those cases where the interpretation of the references in the shared objects is sensitive to the environment.  Loops preserves a complete isolation of environments, with exchange of information permitted only as a knowledge base transaction.  In general, realigning an environment to incorporate changes from another environment requires writing out the changes, clearing the memory in the environments, and re-opening the associated knowledge bases.  In contrast, PIE always shared information between contexts, but it paid the overhead of reinterpreting the symbolic addresses repeatedly at every reference.




























\vfill\end