From: Marty Hall
Subject: Simple CLOS Utility
Date: 
Message-ID: <CIpJ7t.2Gq@aplcenmp.apl.jhu.edu>
I have placed a simple high-level utility for CLOS on ftp.cs.umbc.edu
(130.85.100.53) in /pub/Memoization/CLOS-Utilities.lisp. It basically
defines a macro that lets you do

 (Define-Class Foo (Bar)
   (Slot-1 Val-1)                 
   (Slot-2 Val-2 :Doc-String "Slot-2 string"
                 :type fixnum
                 :allocation :class)
   Slot-3
   ...
   (Slot-N Val-N))

 and get

 (defclass Foo (Bar Named-Object)
   ((Slot-1 :initform Val-1 :accessor Slot-1 :initarg :Slot-1)
    (Slot-2 :initform Val-1 :accessor Slot-2 :initarg :Slot-2
                            :type fixnum :allocation :class)
    (Slot-3                 :accessor Slot-3 :initarg :Slot-3)
    ...
    (Slot-N :initform Val-N :accessor Slot-N :initarg :Slot-N)))

 with the side effect that "Slot-2 string" gets set as doc string for the
 generic function SLOT-2.

The "Named-Object" business automatically gives each instance a unique
NAME slot, lets you retrieve instances based on name, and lets you
retrieve a list of all instances of any given class (that is a Named-Object).

The "Def-Class" macro has the same behavior in that it provides a shorthand
method to define accessors and initargs with the same name as the slot,
but does not name the instances or keep track of the members of each
class. 

A more detailed description of the utilities follows.

						- Marty
(proclaim '(inline skates))

;;;============================================================================
;;; Provides a CLOS class-defining macro, and various utilities that keep
;;; track of instances based on names. 10/92-1/93 Marty Hall.
;;;
;;; A brief overview of the main user routines is given here. See the actual
;;; code for a more detailed explanation, plus functions and macros have doc
;;; strings. 
;;;
;;;   Define-Class: A macro that expands into defclass, allowing an abbreviated
;;;   ============  class definition whereby all slots get accessors with the
;;;                 same name and initargs with the same name except for the
;;;                 colon, and an initform if a value was supplied. It
;;;                 optionally allows the other slot-spec keywords (eg
;;;                 :documentation, :allocation, :type), plus has a special
;;;                 keyword called :Doc-String. This specifies the doc string
;;;                 for the generic function of the same name as the slot. It
;;;                 also adds the mixin "Named-Object" to the list of
;;;                 superclasses, automatically adding a unique NAME slot to
;;;                 each instance, and creating a hash table whereby instances
;;;                 can be retrieved by name. This can eliminate much of the
;;;                 bookkeeping associated with keeping track of instances in
;;;                 variables, plus allows a semantic-net like structure
;;;                 (where instances are stored as values of slots) to be
;;;                 represented in permanent code, since instances do not have
;;;                 a print representation that can be used in code. 
;;;                 See below for more details.
;;;
;;;   Def-Class: Exactly like Define-Class except that it does not add the 
;;;   =========  Named-Object mixin, making instance creation faster but
;;;              providing less utilities on the instances once they are made.
;;;              Syntax is identical to Define-Class.
;;;
;;;   Named-Object: A mixin class that gets added to the superclass list of 
;;;   ============  all classes defined with "Define-Class". It adds a slot
;;;                 and associated reader called Name. The default value of
;;;                 this slot will be :Foo-XX, where Foo is the class name of
;;;                 the instance being created, and XX is the lowest natural
;;;                 number whereby :Foo-XX doesn't already name an instance.
;;;                 All instances of Named-Objects get recorded in a hash
;;;                 table with the name as a key, and get a specialized
;;;                 print-object.
;;;
;;;   Name:         Reader method created automatically for all Named-Objects,
;;;   ====          ie everything created via Define-Class.
;;;
;;;   Get-Instance: A method that normally takes an instance name 
;;;   ============  (:Own-ship, 'Foo-2, etc) as an argument, and returns the
;;;                 instance with that name. The name can be a symbol in any
;;;                 package. Note that this disallows different objects with
;;;                 the same name in different packages, something you might
;;;                 want to do in many applications, but was deliberately left
;;;                 out for simplicity in the [D]ARPA Signature Management
;;;                 System (SMS), for which this utility was made. Returns NIL
;;;                 for a symbol that does not name an instance. If given an
;;;                 instance, it just returns it unchanged. NOTE ALSO the
;;;                 defined macro characters, such that
;;;
;;;                 {Foo} == (Get-Instance :Foo) and
;;;                 [Foo] == (Get-Instance Foo), so that for instance
;;;                 (Depth {Own-Ship}) == (Depth (Get-Instance :Own-Ship))
;;;
;;;   Copy-Instance:  Takes an instance and copies all slot values to another.
;;;   =============   Assumes BOTH instances made via Define-Class in that
;;;                   they have identical slot names, and slot names
;;;                   correspond to accessors. 
;;;
;;;   Assign-Slot-Value: Given a quoted Instance name, Slot name, and value,
;;;   =================  does (setf (Slot {Instance}) Value)
;;;
;;;   Remove-Instance: takes a name or an instance, and removes the 
;;;   ===============  corresponding entries in the hash tables.
;;;
;;;   Remove-Instances: Removes (in the sense above) all instances of a 
;;;   ================  specified class.
;;;
;;;   Direct-Instances: Takes a class name and returns all instances of 
;;;   ================  Named-Objects that are directly (no intervening
;;;                     subclasses) in that class.
;;;
;;;   Instances: Takes a class name and returns all instances of Named-Objects
;;;   =========  are directly or indirectly in that class. Unsorted.
;;;
;;;   Instance-Names: Names of all instances of Named-Objects that are 
;;;   ==============  directly or indirectly in specified class. Sorted
;;;                   alphabetically if the :Sort-p flag is set.
;;;
;;;   All-Instances: All instances of Named-Objects.
;;;   =============
;;;
;;;   All-Instance-Names: Names of all instances of Named-Objects. Sorted
;;;   ==================  alphabetically if the :Sort-p flag is set.
;;;        
;;;   Slot-Names:   Given an instance or a class name, returns a list of all 
;;;   ==========    slots. Assuming the class was defined with Define-Class,
;;;                 this means that every slot SlotJ has a reader function
;;;                 also called SlotJ, and that every slot SlotJ also has a
;;;                 (setf SlotJ) writer, EXCEPT for the "Name" slot.
;;;
;;;  Direct-Slot-Names: Given an instance or a class name, returns list of all
;;;  =================  DIRECTLY defined slots. Ie inherited slots are not
;;;                     included.
;;;
;;;  Has-Reader-p: Given an instance and a slot name, determines if there is
;;;  ============  a reader method with the same name as the slot, as
;;;                Define-Class would make automatically.
;;;  
;;;  Instance-Class: Given an instance name or an instance object returns a 
;;;  ==============  symbol that is the immediate class name. Ie given
;;;                  'Bear-1 returns BEAR. If the argument is neither an
;;;                  instance nor an instance name, this returns NIL.
;;;
;;;  Subclasses: Given a class name returns the names of the direct subclasses.
;;;  ==========  Returns NIL if there are no subclasses OR if the supplied
;;;              symbol names no class. Sorted alphabetically if the :Sort-p
;;;              flag is set.
;;;
;;;  Internal-Address-String: A non-standard way to get the address of an 
;;;  =======================  object in Symbolics or Lucid. Returns it in a
;;;                           string for use by a specialized print-object.
;;;                           NOT portable to other implementations.
;;;
;;;============================================================================