==== CLIPS - object-oriented programming ==== === Class === In object-oriented programming a **class** is a template which describes the common characteristics or attributes of objects. The word template is used in the sense of a tool that is used to build objects having attributes. Each class is an abstraction of a real-worls system or some other logical system that we are trying to model. Class features: * abstraction * inheritance * encapsulation * polymorphism * dynamic binding In order to define a class, you must specify one or more parent classes(called also as a superclass) of the class to be defined. A subclass inherits attributes from one or more superclasses. Classes that inherits builds a trees of classes: CLIPS> (defclass animal (is-a OBJECT)) CLIPS> (defclass mammal (is-a animal)) CLIPS> (defclass bird (is-a animal)) CLIPS> (defclass reptile (is-a animal)) CLIPS> (defclass fish (is-a animal)) CLIPS> (defclass eagle (is-a bird)) CLIPS> (defclass dog (is-a mammal)) CLIPS> (defclass snake (is-a reptile)) CLIPS> (browse-classes animal) animal mammal dog bird eagle reptile snake fish An instance is an object of a class that has values for the attributes. An object's behavior is defined by its message-handlers(handlers). A message-handler for an object responds to messages and performs the required actions. The general form of defclass: (defclass (is-a ) (slot 1) (slot 2) ... (slot N)) For example defclass of a person which store full name, age and sex of a person: CLIPS> (defclass person (is-a USER) (multislot full-name) (slot age) (slot sex (allowed-symbols male female))) CLIPS> (make-instance John of person (full-name John Kowalsky) (age 44) (sex male))) [John] CLIPS> (make-instance Barbara of person (full-name Barbara Nowak) (age 23) (sex female))) [Barbara] CLIPS> (instances) [John] of person [Barbara] of person For a total of 2 instances. CLIPS> (unmake-instance John) TRUE CLIPS> (instances) [Barbara] of person For a total of 1 instance. **make-instance** makes and instances of objects. The basic syntax is as follows: (make-instance [] of ) **unmake-instances** deletes the instance with specified name. **(unmake-instance *)** will remove all instances. It is possible to define more than one instance of object at time - it's usage is similiar s in **deffacts**: CLIPS> (definstances persons (Joey of person (full-name Joey Joe)(age 34) (sex male)) (Amanda of person (full-name Amanda Anderson) (age 45) (sex female))) CLIPS> (instances) CLIPS> (reset) CLIPS> (instances) [initial-object] of INITIAL-OBJECT [Joey] of person [Amanda] of person For a total of 3 instances. What is important, that ony one instance of the same name may be used in a module, and a class cannot be redefined if instances of the class exist. === Messages === The one proper way to communicate with instances is to **send** a message. **(send)** message works anly with target object which has an appropriate handler. CLIPS automatically provides handlers: * print * init * delete * get-xx - get value from xx-named slot * put-xx - put the value to xx slot If you define classes which do not inherit from USER class(such as subclass of INTEGER), you must also create appropriate handlers to carry out all desired tasks such as printing, creating or deleting instances. It is **much easier** to define subclasses of USER. To get value from the instance use **get-xx** function of **send**, to put another value to the slot use **put-xx**: CLIPS> (send [Barbara] get-full-name) (Barbara Nowak) CLIPS> (send [Barbara] put-full-name Barbara Kowalsky) (Barbara Kowalsky) CLIPS> (send [Barbara] print) [Barbara] of person (full-name Barbara Kowalsky) (age 23) (sex female) To modify more than one slot of instance it is needed to use **modify-instance** function; CLIPS> (modify-instance [Barbara] (full-name Basia Kowalsky) (age 24) (sex female)) TRUE CLIPS> (send [Barbara] print) [Barbara] of person (full-name Basia Kowalsky) (age 24) (sex female) === Handlers === CLIPS allows you to define your own message-handlers(see also **polymorphism**). The general format of a message-handler is as follows: (defmessage-handler [handler type] [optional-comment] (* [wildcard-parameter]) *) Note, that only value of the last action is returned. **Handler-type** tell when to execute the handler. the handler types are listed in the order that they are normally called during execution of message: * around - set up environment for the other handlers, it returns a value * before - some work before primary, it does not return value * primary - major task of a message, it returns a value * after - some work after primary(for example cleaning), it does not return value Simple message-handler to add values of two NUMBER objects: (defmessage-handler NUMBER + (?arg) (+ ?self ?arg)) Now we are able to send message **+**: CLIPS> (send 3 + 11) 14 **?self** is a special variable in which CLIPS stores the active instance. It is used to get values from slots using **:** operator. Go get slot of current instance just type **?selfL** just like in an example below: CLIPS> (defclass person (is-a USER) (multislot full-name) (slot age (type NUMBER)) (slot sex)) CLIPS> (make-instance Amy of person (full-name Amy Johnson) (age 35) (sex female)) [Amy] CLIPS> (make-instance John of person (full-name John Donatello) (age 20) (sex male)) [John] CLIPS> (defmessage-handler person write-age () (printout t "The age of " ?self:full-name " is " ?self:age crlf)) CLIPS> (send [Amy] write-age) The age of (Amy Johnson) is 35 CLIPS> (send [John] write-age) The age of (John Donatello) is 20 **self** parameter allow you to read a slot value. To write a slot value use the **bind** function. The **?self:** notation is more efficient that sending messages but can only be used from within a handler on its active instance. The alternative way is to use **dynamic-get** and **dynamic-put**: CLIPS> (defmessage-handler person write-age-2 () (printout t "The age of " (dynamic-get full-name) " is " (dynamic-get age) crlf)) CLIPS> (send [Amy] write-age-2) The age of (Amy Johnson) is 35 The ?self:age can only be used in a class and its subclasses which inherit the slot age. It is evaluated in static way - if a subclass redefines a slot, a superclass message-handler will fail if it tries to directly access the slot using ?self:. **dynamic-get** and **dynamic-put** check slots dynamically. Example: CLIPS> (defmessage-handler person change-name-to ($?new-name) (bind ?self:full-name ?new-name)) CLIPS> (send [Amy] change-name-to Amy Whitehouse) (Amy Whitehouse)