Lecture of 26 January 1996

Classes and Methods in Dylan

The language Dylan was defined by a group at Apple Computer's Cambridge Research Laboratories. A book describing an early version of the Dylan language (Andrew Shalit, Dylan: an object oriented dynamic language, Apple Computer, Inc. 1992) put forth the reasons Apple embarked upon development of a new Object-Oriented Dynamic Language.

According to Larry Tesler [Dylan, 1992], Dylan was intended to meet the following requirements:

A Dylan program consists of one or more libraries, which are the units of compilation and optimization in a Dylan program. Libraries contain modules, which are Dylan's unit of global name scoping. A binding is an association of a name to a value within a module. Both variable and constant bindings can be defined.

A Dylan class describes the structure of the objects that belong to the class by enumerating the slots (conceptual instance variables) that comprise the objects and by specifying their getters and setters. Consider the playing card class.

define constant <suit> :: <type> = one-of (#"hearts", #"clubs", #"diamonds", #"spades"); define constant <color> :: <type> = one-of (#"red", #"black"); define class <card> (<object>) slot suit :: <suit>; slot rank :: <integer>; virtual slot color :: <color>; end class <card>;

The program fragment presented here contains three constituents:

Dylan distinguishes between the notion of a class and a type. A class describes a set of objects with common structure created by class definitions. Type is a more general notion encompassing classes, unions of classes, sets of values, and other constructs.

By convention, type names in Dylan are written within angle brackets (like <suit>).

The syntactic construct #"name" is used to introduce a unique symbolic name, and the function one-of creates a type containing exactly the values presented as arguments to it. Thus <suit> is a type containing just the values #"hearts", #"clubs", #"diamonds", and #"spades" and no others.

The class definition of <card> specifies that an object belonging to that class has unique superclass <object>, and constains three slots, namely:

The suit and rank slots identify the data members belonging to every instance object of the class <card>. They can be accessed through the use of getter and setter methods. The slot color is virtual, thus there is no actual data member to hold this value in instances of <card>. However, by identifying the virtual slot, the programmer is documenting the fact that color getter or setter methods will be provided by the program, thus giving the appearance that there is a real color slot.

The definition of the color getter method uses the suit getter method to satisfy its requirements.

define method color (c :: <card>) => <color>; if (c.suit == #"diamonds" | c.suit == #"hearts") #"red" else #"black" end if; end method color;

Note the way in which the color method is defined and note the syntax for accessing the suit slot. The syntax object.name is the conventional way in which a getter is invoked. It is functionally identical to a call of the the form name(object). Thus to define the color getter method, we describe how to implement the generic function color when it is applied to an object belonging to class .

Dylan's Differing World View

The fundamental difference between the Dylan view of object behavior and that espoused by Smalltalk hinges on how one elicits behavior. In the Smalltalk view, classes contain an enumeration of the data members each instance will contain and also contain the methods used by the class to implement messages it will receive. The Dylan view, removes the methods from the classes, and groups them together in what are termed generic functions. A generic function is associated with the methods which implement it, rather than associating methods with the objects.

Dylan's view, though characterized by some as non-OO, supports a valid and reasonable view of how to achieve computation in an OO framework. In particular, Dylan's view solves problems associated with more traditional message-passing implementations. (See the double-dispatch work-around cited by Budd in Chapter 8 as an example of something that can be avoided easily in Dylan.) Dylan's view also supports multiple-inheritance in a straighforward and principled way.

This document is copyright 1996 by Joseph N. Wilson.