CLOS Guild Battleship

Lisp Dialect

Common Lisp

Synopsis

Common Lisp has the most sophisticated object-oriented programming framework of any major programming language, called the Common Lisp Object System (CLOS). It is customizable at a fundamental level using the Metaobject Protocol (MOP). There’s really nothing like it anywhere else in programming. It lets you create incredibly complex software without losing control over the code.

image with no caption

How It Kills Bugs

Object-oriented programing (OOP) is a commonly used technique for keeping bugs under control. By writing code in an object-oriented style, you can decouple different parts of your code. When you decouple code, you break your code into logical components, which can be tested independently.

Example A-6. Example 1: Wrapping Code Around Methods

 (defclass widget ()
      ((color :accessor widget-color
                :initarg :color)))
 (defmethod describe-widget ((w widget))
     (format t "this is a ˜a widget" (widget-color w)))
 (defmethod describe-widget :before ((w widget))
    (add-to-log "Somebody is checking on a widget"))

The basic concepts behind object-oriented programming in Common Lisp are discussed in Chapter 9. For detailed information on the design of CLOS, I recommend reading the CLOS papers compiled at http://www.dreamsongs.com/CLOS.html.

Explanation

For this example, imagine we run a company that sells widgets, and we need some object-oriented Lisp code to help keep track of them. First, we need to create a new CLOS class (called widget) with defclass . It has one property (or slot, in Lisp lingo) describing the widget’s color. Next, we declare a describe-widget, which prints out a description of the widget . By convention, a function designed to operate on a specific type of object is called a method. In this case, the describe-widget is considered a method of the widget object.

Now suppose we want to write an entry to a log file every time a user checks on a widget. Using the CLOS, we can declare one or more before methods that will automatically be called before the main describe-widget method is executed .

If we didn’t have before methods available, we would need to dirty up our main widget code to add logging, like so:

 (defmethod describe-widget ((w widget))
   (add-to-log "Somebody is checking on a widget")
    (format t "this is a ˜a widget" (widget-color w)))

Here, we’ve added the command for logging right in the middle of the describe-widget method . This code is a lot uglier, because writing to logs has nothing intrinsically to do with describing a widget. The logging in this version is also tightly coupled to the main code, which means we can no longer test the widget code independently from the debugging code. Using the before method leads to cleaner, more decoupled code.

Explanation

This example demontrates multiple dispatch, a powerful technique for writing methods that are chosen based on the types of their parameters.

Example A-7. Example 2: Multiple Dispatch

 (defclass color () ())
 (defclass red (color) ())
  (defclass blue (color) ())
  (defclass yellow (color) ())

 (defmethod mix ((c1 color) (c2 color))
      "I don't know what color that makes")

 (defmethod mix ((c1 blue) (c2 yellow))
    "you made green!")

 (defmethod mix ((c1 yellow) (c2 red))
    "you made orange!")

The example begins by creating a color class and also defines three derived classes: red, green, and blue . Then we declare a mix method, which will tell us what happens if we mix any two colors. By default, when we mix two colors, it just says, “I don’t know what color that makes” . However, using multiple dispatch, we can define more versions of the mix method. For instance, we can declare a version that mixes blue and yellow , and another version for yellow and red . Here’s what happens when we call these methods with different colors:

> (mix (make-instance 'red) (make-instance 'blue))
"I don't know what color that makes"
> (mix (make-instance 'yellow) (make-instance 'red))
"you made orange!"

The important thing to note about the example is that in order to figure out which mix method to call in a given situation, the CLOS needs to take into account both of the objects passed into the method. It is dispatching to a specific implementation of the method based on the types of multiple objects. This is a feature that is not available in traditional object-oriented languages, such as Java or C++.

Weakness

Opinions vary widely in the Lisp community as to how large a role object-oriented techniques should play in programming. The critics of this style complain that object-oriented techniques force data to be hidden away in lot of disparate places by requiring them to live inside many different objects. Having data located in disparate places can make programs difficult to understand, especially if that data changes over time. Therefore, many Lispers prefer to use functional techniques over object-oriented techniques, though the two can often be used together with some care. Nonetheless, there are still many domains in which object-oriented techniques are invaluable, such as in user interface programming or simulation programming.

image with no caption
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.187.210