Objects, slots, methods, functions, and arguments

+ Associated example files


slippery chicken is written in and functions on the principles of the Common Lisp Object System (CLOS), the Common Lisp facility for object-oriented programming. While the user isn't required to understand the details of CLOS in order to be able to use slippery chicken, a brief introduction to a few core principles may help the beginning user to grasp some of the nomenclature and concepts found in the manual.

Like many other object-oriented languages, the basic building blocks in CLOS are classes and methods. The source code documentation for slippery chicken includes indexes for all of its classes and their associated methods.

+ Classes and slots

A class in slippery chicken, put very simply, is a generic blueprint for a type of container that holds a specific number of specific types of data. A class itself is essentially an empty copy of this type of container, with empty slots for the various items of data it is designed to store.

The user (or various internal routines in the software) can then create any number of objects using this blueprint. Each object made using this blueprint (each instance) will be a separate entity, but each will have the same structure, as defined in the blueprint for the class, and each will possess the same slots, which will contain specific data when the object is made. Once an object is created, the data in its slots can either be read or modified.

For example, the named-object class, which is the fundamental class in slippery chicken from which all other classes are derived, has the slots id, tag, and data:

(defclass named-object ()
  ((id :accessor id :initarg :id :initform nil)
   (tag :accessor tag :initarg :tag :initform nil)
   (data :accessor data :initarg :data :initform nil)))

Subclasses and inheritance

Classes can also be defined as subclasses of an already existing class. Subclasses too, in turn, can be parent classes of further subclasses. Any class that is a subclass of another class also inherits the slots of its parent class in addition to the slots that its own definition specifies. Thus, in addition to its own warn-not-found slot, the assoc-list class, for example, also inherits all of the slots of named-object, linked-named-object, sclist, and circular-sclist, from which it derives. Since all classes in slippery chicken derive from the named-object class, they all also have the slots id, tag, and data, even though these are not specified in the class definition.

(defclass assoc-list (circular-sclist)
  ((warn-not-found :accessor warn-not-found :type boolean :initarg
                   :warn-not-found :initform t)))

Making instances of class objects

Instances of class objects are created by using the CLOS make-instance function and passing values to the object's slots using its slot accessor names as keyword arguments. In addition, slippery chicken also has several built-in functions (all starting with the word make-) to facilitate creating instances of various class objects. The latter is the recommended means of creating objects and is described in more detail below.

(make-instance 'assoc-list :id 'al-examp :data '((3 17) (ob bf3) (c4 q)))

ASSOC-LIST: warn-not-found T
SCLIST: sclist-length: 3, bounds-alert: T, copy: T
LINKED-NAMED-OBJECT: previous: NIL, this: NIL, next: NIL
data: (
NAMED-OBJECT: id: 3, tag: NIL, 
data: 17

NAMED-OBJECT: id: OB, tag: NIL, 
data: BF3

NAMED-OBJECT: id: C4, tag: NIL, 
data: Q


+ Methods

Methods in slippery chicken are the actions that can be performed on the data contained in a class's slots. Some methods generate the data to be placed into the slots. Other methods manipulate data already stored there, and others just read and retrieve the data already stored there. For example, the get-first method of the assoc-list class, which stores a list of items in its data slot, reads and retrieves the first item stored in that list:

(defmethod get-first ((al assoc-list))
  (first (data al)))

An example of using a method. The class object must have already been created.

(let* ((al-object-1 
       (make-instance 'assoc-list 
                      :id 'al-object-1 
                      :data '((3 17) (ob bf3) (c4 q)))))
  (get-first al-object-1))

NAMED-OBJECT: id: 3, tag: NIL, 
data: 17

As with slots, methods too are inherited from parent classes.


+ Functions and arguments

Functions are routines that perform a predefined sequence of operations. Many of the functions in slippery chicken employ one or more methods. Functions can incorporate external values that are passed to them as arguments. These values can be the result of other routines, or may be specified by the user when the function is used. Some arguments are required, and some are optional.

Keyword arguments

One of the most frequent types of optional arguments used in slippery chicken is the keyword argument. None of the keyword arguments associated with a function must be called in order to use that function, but if one is used, the keyword itself must also be specified. In order to use a keyword argument in Common Lisp, it must be preceded by a colon.

The get-harmonics function, for example, takes the required argument fundamental, and has the optional keyword arguments start-at, min-freq, and max-freq, (which have default values of 1, 20, and 20000, respectively):

(defun get-harmonics (fundamental &key (start-at 1) (min-freq 20)
                      (max-freq 20000))

If the user wanted to employ this function and opt to specify values for the start-at and max-freq arguments, that would be done like so:

(get-harmonics 63 :start-at 2 :max-freq 1010)

=> (126 189 252 315 378 441 504 567 630 693 756 819 882 945 1008)

The source code documentation includes an index of all of the slippery chicken functions.


+ The make- functions

Nearly every class in slippery chicken has a function associated with it that provides an easier way for the user (or the software) to create objects of that class. These functions can be recognized by the fact that their names start with make-.

Many of the make- functions have keyword arguments that can be used to set the values for the most important slots of the class with which they are associated. In these cases, the given keyword arguments are usually identical to the corresponding slot names.

For example, the rhythm class has 23 different slots. The associated make-rhythm function has keyword arguments for two of them, namely is-rest and is-tied-to. (The third and fourth keyword arguments, duration and tempo, are not used to directly set the value of a corresponding slot).

(defun make-rhythm (rthm &key (is-rest nil) (is-tied-to nil) (duration nil)
                    (tempo 60.0))

The user can employ this function to make a rhythm object, and can opt to specify values for these slots of that object by setting the function's keyword arguments accordingly:

(make-rhythm 16 :is-rest t)

RHYTHM: value: 16.000, duration: 0.250, rq: 1/4, is-rest: T, 
        score-rthm: 16.0, undotted-value: 16, num-flags: 2, num-dots: 0, 
        is-tied-to: NIL, is-tied-from: NIL, compound-duration: 0.250, 
        is-grace-note: NIL, needs-new-note: NIL, beam: NIL, bracket: NIL, 
        rqq-note: NIL, rqq-info: NIL, marks: NIL, marks-in-part: NIL, 
        letter-value: 16, tuplet-scaler: 1, grace-note-duration: 0.05
LINKED-NAMED-OBJECT: previous: NIL, this: NIL, next: NIL
NAMED-OBJECT: id: 16, tag: NIL, 
data: 16


+ make-slippery-chicken

The make- function that the user will most frequently employ is make-slippery-chicken. This function is used to make an object of the slippery-chicken class (often referred to in this manual as a "slippery-chicken object").

The slippery-chicken class currently has 29 slots, many of which will contain objects of other classes when the slippery-chicken object itself is made, such as an instrument-palette object, an ensemble object, and a rthm-seq-palette object, to name just a few. Many of the methods associated with the slippery-chicken class are used to make instances of these sub-objects, or to set, read, and modify the data they contain.

The make-slippery-chicken function currently has 25 optional keyword arguments, most of which are used to directly set the data contained in slots of the same name. Thus, when using the make-slippery-chicken function to create a composition, the various blocks of code described in this User Guide will begin with a colon, as they are the keyword arguments for the function. As most of these keyword arguments are used to directly set the value of a slot with the same name, it will often occur in this manual that reference is made to the "instrument-palette slot", for example, rather than the ":instrument-palette keyword".

Example of the simplest call to make-slippery-chicken:

(let* ((mini
        :ensemble '(((vn (violin :midi-channel 1))))
        :set-palette '((1 ((c4 e4 g4))))
        :set-map '((1 (1)))
        :rthm-seq-palette '((1 ((((2 4) q e e))
                                :pitch-seq-palette ((1 2 3)))))
        :rthm-seq-map '((1 ((vn (1))))))))
  (midi-play mini)
  (cmn-display mini)
  (write-lp-data-for-all mini))

More information can be found about the specific classes, slots, methods, and associated functions in the source code documentation.