3.10. Objects


All atoms are stored as pairs (class, instance). The class component provides informations about the general properties of that kind of atom. The instance component contains the properties of this specific atom in particular. Classes themselves are unnamed atoms, stored as value of certain symbols. For example, classes are instances of the class class (i.e. of the class stored as the value of the symbol class ).



3.10.0. Object Terminology


A class defines two major kinds of information:

In addition, predefined classes associated with standard Lush objects often have hidden properties. Such classes are special and do not inherit from the object class. For example, a symbol has some storage for its value; the storage is not a slot. A symbol also returns its value when it is evaluated; this behavior is not a method.



3.10.1. Inheritance


New classes defined with the defclass function are always subclasses of another class (i.e. its superclass). The superclass itself may have its own superclasses. In this way:



3.10.2. Predefined Classes


Here is a compact list of the main predefined classes. Most of them are named using uppercase symbols, which ought to be surrounded with bars to avoid the usual lowercase conversion:

All user defined classes must be direct or indirect subclasses of the class object . You cannot inherit a predefined class like |SYMB| , it is not a subclass of object . The object class defines a regular lisp object with no hidden properties. Instances of subclasses of the class object are easily created with the function new .



3.10.3. Defining a Class




3.10.3.0. (defclass name superclass s1 ... sn)
[DM]


Defines a subclass of class superclass with slots s1 ... sn . The class is stored into symbol name , which is returned. Slot specifications s1 ... sn can be symbols or lists (symbol default) which indicate initial values assigned to the slots of a new object.

Example:

 ;;; Creates a class <rect> with two slots: <width> and <height>.
 ? (defclass rect object
     width height )
 = rect
 ;;; Creates a subclass of <rect>,
 ;;; plus an additional slot <name> with default value <"noname">.
 ? (defclass namedrect rect
     (name "noname") )
 = namedrect
  



3.10.3.1. (makeclass classname superclass slotnamelist slotdefaultlist)
[DX]


This a lower-level function to create a new class named classname . Most user will prefer to use defclass instead. The new class inherits class superclass . List slotnamelist contains the names of the additional slots defined by the new class. List slotdefaultlist contains the default values for these slots. Both lists are in reverse order (i.e. the first slot in the list appears last when pretty-printing the class). This function does not set the value of symbol classname , use the macro function defclass for that purpose.



3.10.3.2. (classname c)
[DX]


Returns the name of class c , i.e the symbol with the corresponding value that was set by defclass .

Example:

 ? (classname rect)
 = rect
  



3.10.3.3. (slots c)
[DX]


Returns the list of the slots defined for class c .

Example:

 ? (slots rect)
 = (width height)
 ? (slots namedrect)
 = ((name "noname"))
  



3.10.3.4. (methods c)
[DX]


Returns the list of all method names defined for class c .



3.10.3.5. (super c)
[DX]


Returns the superclass of class c or the empty list if c has no superclass.

Example:

 ? (super rect)
 = ::class:object
 ? (classname (super namedrect))
 = rect
  



3.10.3.6. (subclasses c)
[DX]


Returns the list of all subclasses of class c . When argument c is the empty list subclasses returns the list of root classes, i.e. classes without superclass.

Example:

 (subclasses object)
  



3.10.4. Creating Objects




3.10.4.0. (new class ... args ...)
[DY]


Creates a new instance of a subclass class of the class object .

If no constructor method is defined no arguments are allowed. If a constructor method is defined for class class a construction message is sent to the new object with arguments args .

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Creates instances of classes <rect> and <namedrect>.
 ? (setq r (new rect))
 = ::rect:06fa0
 ? (setq nr (new namedrect))
 = ::namedrect:06fe8
  
This function only works when creating instances of subclasses of class object . It is not possible to directly create instances of subclasses of other predefined classes.



3.10.4.1. (new-empty class)
[DX]


Creates a new instance of class class without calling the constructor. All slots are initialized to () .

Use this function with care because the empty object might trump the expectations of other code working with this class.



3.10.4.2. (new-copy object)
[DX]


Creates a copy of the user defined object object . The copy is an instance of the same class with all slots initialized to the same values. The contents of the slots are not copied. This is equivalent to:
 (let* ((c (classof object))
        (n (new-empty c)) )
   (setq :n:slot1 :object:slot1)
   (setq :n:slot2 :object:slot2)
   ...
   (setq :n:slotN :object:slotN)              
   n )
  
Use this function with care because other code working with this class might not be able to deal with multiple copies of the same object. Calls to destructors are particularly problematic.



3.10.4.3. (delete x)
[DX]


Deletes the Lush object x .

The operation of this function is somewhat tricky because all other references to object x must be converted to references to the empty list.

If destructor methods are defined for an object then destruction messages are sent. Object x is then converted to an instance of the class |ZOMBIE| . During its normal operation, the interpreter recognizes these zombies and always replaces a reference to a zombie by a reference to the empty list.



3.10.4.4. (classof x)
[DX]


Returns the class of an object x .

Example:

 (classof (new object))
  



3.10.4.5. (is-of-class x class)
[DX]


Tests if the class of object x of any of its superclass is equal to class class .

Example:

 ? (is-of-class nr rect)
 = t
  



3.10.5. Accessing Slots


There are various ways to read or change the values stored in the slots of an object. Changing the value stored in a slot changes the object in a way comparable to rplaca and rplacd , in the case of lists. This change will be reflected through all pointers referring to the same object.

See: (== n1 n2 )



3.10.5.0. :obj:slot1...:slotn
[DMC] (sysenv.lsh)


See: (scope obj slot1 ... slotn )
See: (scope symb )
This macro character is expanded as a call to the scope function.



3.10.5.1. (scope obj slot1 ... slotn)
[DY]


See: : obj : slot1 ...: slotn
See: (scope symb )
The simplest method for setting or getting the slots of an object is called the scope macro . The syntax :obj:slot refers to the slot slot of object obj . Actually, the scope macro character converts expression :obj:slot into a list (scope obj slot) .

When this list is evaluated the scope function returns the value of slot slot of object obj . Moreover, most functions that affect the value of a symbol recognize such a list as a reference to slot slot of object obj .

Nested scope macros are allowed: :obj:slot_1:slot2 refers to slot slot2 of the object contained in slot slot1 of object obj .

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ? (setq :nr:name "myrectangle")
 = "myrectangle"
 ? (setq :nr:width  8 
         :nr:height 6 )
 = 6
 ? (print :nr:width :nr:height :nr:name)
 8 6 "myrectangle"
 = "myrectangle"
  



3.10.5.2. (scope symb)
[DY]


See: (scope obj slot1 ... slotn )
See: : obj : slot1 ...: slotn
The scope macro has another important use as the unary scope macro . Expression :symb is converted into list (scope symb) which refers to the global value of symbol symb .

Example:

 ? (defvar x 3)
 = 3
 ? (let ((x 8))
     (print :x)
     (setq :x 6)
     (print x) )
 3
 8
 = 8
 ? x
 = 6
  



3.10.5.3. (letslot [class] obj l1 ... ln)
[DY]


See: (scope obj slot1 ... slotn )
See: this
Calls function progn on l1 ... ln , within the scope of object obj , and returns the last result. Within the object scope each slot of the object, either defined by its class or inherited from its superclasses, can be directly accessed as the value of its symbolic slot name.

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ? (setq width ())
 = ()
 ? (letslot r
     (setq width 4)
     (setq height 5) )
 = 5
 ? width
 = ()
 ? (letslot r (* width height))
 = 20
  
Within an object scope the symbol this always refers to object itself.

The optional argument class must be the object class or one of its superclasses. The only visible slots are then defined by class class and its superclasses. This can make a difference when obj is an instance of a subclass of class .



3.10.6. Defining Methods




3.10.6.0. (defmethod class symb args . body)
[DM] (sysenv.lsh)


See: Argument List
See: (==> obj symb ... args ... )
Defines a method named symb for class class . Argument symb must be a symbol and is not evaluated. Argument args must be a valid argument list.

When an instance of class class receives a message whose selector is symb the body body of the method is executed with a call to function progn . During this execution the slots defined by class and its superclasses are bound to their symbolic names, as in letslot , and the arguments of the message are evaluated and bound to the symbols in argumentlist args .

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ;;
 ;; This is a method for computing the surface of a rect.
 ? (defmethod rect surface()
     (* width height) )
 = surface
 ;; a method for printing  n times the name of a namedrect
 ? (defmethod namedrect showname(n)
     (repeat n (print name)) )
 = showname
  



3.10.6.1. (demethod class symb args . body)
[DM] (sysenv.lsh)


Identical to defmethod .



3.10.6.2. (dfmethod class symb args . body)
[DM] (sysenv.lsh)


Defines an flambda-method named symb for class class . flambda-methods do not evaluate their arguments, unlike regular methods defined with demethod or defmethod.



3.10.6.3. (dmmethod class symb args . body)
[DM] (sysenv.lsh)


Defines an mlambda-method named symb for class class . mlambda-methods are to regular methods what macros (defined with dm or mlambda ) are to regular functions (defined with de or lambda ).



3.10.6.4. (putmethod class symb func)
[DX]


Add method symb to class class . func must be a lambda, flmabda, or mlambda.



3.10.6.5. (pretty-method class symb)
[DE] (sysenv.lsh)


Prints a nicely indented definition of method symb of class class .



3.10.7. Sending Messages




3.10.7.0. (==> obj symb ... args ... )
[MSG]


Sends a message whose selector is symb to object obj , with arguments args .

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ;; Method <surface> is defined as an example for <defmethod>.
 ;;
 ;; Send a surface message to rect <r>
 ? (==> r surface)
 = 20
 ;; Send a showname message to namedrect <nr>
 ? (==> nr showname 2)
 "myrectangle"
 "myrectangle"
 = "myrectangle"
 ;; Send a surface message to namedrect <nr>
 ;; The method is inherited from superclass <rect>
 ? (==> nr surface)
 = 48
  
When an object receives a message its method is executed in the object scope defined by the class that owns the method: If the method is defined by a superclass only the slots of that superclass and of its superclasses are directly referred to by their names.

When no method symbol is defined in the class or superclasses a method named -unknown is searched for. Once found, the -unknown method is executed with two arguments: the initial method name symb and the list of the evaluated arguments args . An error occurs if method -unknown is not defined.



3.10.7.1. (==> obj (class . symb) ... args ... )
[MSG]


This construction is known as a cast-and-send . A message with selector symb and arguments args is sent to the object obj , considered as an instance of class class . Methods are searched for in class class and its superclasses, instead of the class of obj and its superclasses.

Argument class is evaluated and must return a superclass of the class of obj . Argument symb is not evaluated and must be a valid method selector for class class .

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ;; Method <surface> is defined as an example for <defmethod>.
 ;;
 ;; Override surface method of class rect
 ? (defmethod namedrect surface()
        ;; prints the name by sending a showname message
        (==> this showname 1)
        ;; returns 1+ the result of the surface method of class rect
        (1+ (==> this (rect . surface))) )
 = surface
 ? (==> nr surface)
 "myrectangle"
 = 49
 ;; Still call the surface method of class rect
 ? (==> nr (rect . surface))
 = 48
  



3.10.7.2. this


See: (letslot obj l1 ... ln )
See: (==> obj symb ... args ... )
While Lush is executing a method you can use symbol this to refer to the object receiving the message.



3.10.7.3. (check==> class symb)
[DX]


Searches class class and its superclasses for a method whose selector is symb . If a matching method exists this function returns the method as a DF function.

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ;; Method <surface> is defined as an example for <defmethod>.
 ;;
 ;; There is no method yoyo in rect
 ? (check==> rect 'yoyo)
 = ()
 ;; there is a method surface in rect
 ? (check==> rect 'surface)
 = DF:0604c
  



3.10.7.4. (apply==> obj symbol args)
[DX]


Sends message symbol to object obj with the list args as arguments.



3.10.8. Constructors and Destructors


See: (new class ... args ...)
See: (delete x )
Constructors are specific methods whose selector is the name of their class, as returned by the function classname . Constructors are useful for easy initialization of an object during its creation.

Whenever a new object is created, with the new function, a construction message is sent to the new object. The optional arguments of the new function are sent as arguments to the construction message.

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Method <surface> is defined as an example for <defmethod>.
 ;;
 ;; Define a constructor for class rect
 ? (defmethod rect rect(w h)
     (setq width w)
     (setq height h) )
 = rect
 ;; creates a new rectangle
 ? (setq r (new rect 8 9))
 = ::rect:06fb8
 ;; sends a surface message
 ? (==> r surface)
 = 72
  
The function new only calls a constructor when it is defined by the class of the newly created object. However, constructors can call the constructor method of their superclass.

Example:

 ;; defines a constructor for class namedrect
 ? (defmethod namedrect namedrect(w h n)
     ;; explicitely calls the constructor of class rect.
     (==> this rect w h)
     (setq name n) )
  
Destructors are specific methods whose selector is -destructor . When an object is deleted all the destructors of its class and superclasses are successively called. Deletion occurs when the function delete is called on an object or when the garbage collection mechanism proves that an object will no longer be accessed.

Note: Only objects created with function new receive destruction messages. Numbers, strings, and symbols usually do not receive such messages.

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ;; Method <surface> is defined as an example for <defmethod>.
 ;;
 ;; Defines a destructor for the rect class
 ? (defmethod rect -destructor()
     (printf "rect destructor on %l\n" this) )
 = -destructor
 ;; Defines a destructor for the namedrect class
 ? (defmethod namedrect -destructor()
     (printf "namedrect destructor on %l (%s)\n" this name) )
 = -destructor
 ;; deletes objects r and nr
 ? (delete r)
 rect destructor on ::rect:06fb8
 = ()
 ? r
 = ()
 ? (delete nr)
 namedrect destructor on ::namedrect:06fe8 (myrectangle)
 rect destructor on ::namedrect:06fe8
 = ()
 ? nr
 = ()
  
Destructors allow objects to perform some housekeeping before they disappear.



3.10.9. Predefined Methods




3.10.9.0. (==> obj pname)
[MSG]


See: (pname l )
The function pname returns a string that describes a lisp object. When executing this function Lush searches the object for a method pname before applying the hardcoded defaults. Overriding method pname lets you redefine how Lush prints certain objects.

Example:

 ;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
 ;; Objects <r> and <nr> are defined as examples for <new>.
 ;; Method <surface> is defined as an example for <defmethod>.
 ;;
 ;; Defines a pname function for the rect class
 ? (defmethod rect pname()
     (sprintf "<rectangle %d by %d>" width height) )
 = pname
 ? (new rect 8 6)
 = <rectangle 8 by 6>
  



3.10.9.1. (==> obj print)
[MSG]


See: (prin l1 ... ln )
When Lush prints an object with function prin or print it searches for a method print before applying hardcoded defaults based on function pname .

It is a good idea to override method print instead of method pname when large amounts of text are necessary (e.g. in the case of matrices).



3.10.9.2. (==> obj pprint)
[MSG]


See: (pprin l1 ... ln )
When Lush prints an atom with function pprin or pprint it searches for a method pprint before applying the hardcoded defaults.



3.10.9.3. (==> obj pretty)
[MSG]


See: (pretty f )
Function pretty displays an object by sending them a message pretty . The default method pretty defined by class object displays the slots of the object. Specific pretty methods are also defined for functions, symbols, classes, and so forth.



3.10.9.4. (==> obj -destructor)
[MSG]


See: Constructors and Destructors
This method is invoked when the object is destroyed.



3.10.9.5. (==> obj -unknown symb args)
[MSG]


See: Sending Messages
This method is invoked when a message symb is sent to an object obj whose class or superclasses do not define a suitable method. Argument args is the list of message arguments the object is destroyed. An error message is produced when this method is not defined.



3.10.9.6. (==> obj -call args)
[MSG]


This method is invoked when the object obj is used like a function as the first element of a list to be evaluated. Argument args contains the arguments of the calling form. An error message is produced when this method is not defined.