[Next] [Previous] [Up] [Top] [Contents] [Index]

5 Types and Classes


Classes are used to define the inheritance, structure, and initialization of objects.

Every object is a direct instance of exactly one class, and a general instance of the general superclasses of that class.

A class determines which slots its instances have. Slots are the local storage available within instances. They are used to store the state of objects.

Classes determine how their instances are initialized by using the initialization protocol.

Features of Classes

There are four features of classes, each of which is independent of the others.

Creating Classes

New classes may be created by calling make on <class>, or with the definition define class. In most programs the latter is more commonly used.

When a class is created with make, it is instantiated and returned just like any other object. The options available when creating a class with make are described on page 184.

When a class is created with define class it is used to initialize a new module binding. define class allows the specification of superclasses, slots, initialization behavior, and options related to sealing. The complete syntax of define class is given on page 364.

The following simple class definition creates a class named by the module binding <new>. The class inherits from <object>, and does not specify any slots.

define class <new> (<object>)
end class <new>;
The following class definition illustrates the creation of a class with multiple superclasses. Again, there are no slots.

define class <color-window> (<palette>, <window>)
end class <color-window>;

Class Inheritance

When a class is created, its direct superclasses are specified. The new class directly inherits from these classes; it is a direct subclass of each of these classes. There can be no duplicates in the direct superclasses of a class.

The subclass relationship is transitive. If a class C is a direct subclass of C1, C1 is a direct subclass of C2, and C2 is a direct subclass of C3, then C is an indirect subclass of C2 and C3. A general subclass is a direct or indirect subclass.

Inheritance cannot be circular. A class cannot be its own general subclass.

A class is a subtype of each of its general superclasses.

Every class is a general subclass of <object>.

Computing the Class Precedence List

The definition of a class specifies a total ordering on that class and its direct superclasses. This ordering is called the local precedence order. In the local precedence order, the class precedes its direct superclasses, and each direct superclass precedes all other direct superclasses following it in the sequence of direct superclasses given in the class definition.

The class precedence list for a class C is a total ordering on C and its superclasses that is consistent with the local precedence orders of each of C and its superclasses as well as with the ordering in the class precedence list of each of its superclasses.

Sometimes there are several possible total orderings on C and its superclasses that are consistent with the local precedence orders for each of C and its superclasses. Dylan uses a deterministic algorithm to compute the class precedence list, which chooses one of the possible total orderings.

Sometimes there is no possible total ordering on C and its superclasses that is consistent with the local precedence orders for each of C and its superclasses. In this case, the class precedence list cannot be computed, and an error is signaled.

To compute the class precedence list for class C:

define method compute-all-superclasses (c :: <class>)
  let local-precedence-order-constraints
    = add!(compute-constraints(c.direct-superclasses),
           list(c, first(c.direct-superclasses)));
  let monotonicity-constraints
    = reduce1(concatenate,
              map(compose(compute-constraints, all-superclasses),
  let constraints
                        test: \=);
  let all-supers
    = reduce(union, list(c),
             map(all-superclasses, c.direct-superclasses));
  topological-sort(all-supers, constraints, tie-breaker-rule)
end method compute-all-superclasses;
// Given an ordered list, pair up adjacent elements to give the  
// constraint set for the ordering.
define method compute-constraints (l :: <list>)
  if (empty?(l) | empty?(l.tail))
    pair(list(l.first, l.second), compute-constraints(l.tail))
end method compute-constraints;

define method topological-sort
    (elements :: <list>,
     constraints :: <list>,
     tie-breaker :: <function>)
  local method sort (remaining-constraints,
          local method next-minimal-elements
                            (remaining-elements :: <list>)
                  choose(method (class)
                                       test: method (a, b)
                                                  a == b.second
                                                 end method)
                              end method,
                end method next-minimal-elements;
          let minimal-elements =
          if (empty?(minimal-elements))
            if (empty?(remaining-elements))
              error("Inconsistent precedence graph ~S.", 
            end if
            let choice =
                if (empty?(minimal-elements.tail))
                  tie-breaker(minimal-elements, result)
                end if;
                          test: method (a, b) member?(b, a) end),
                 remove(remaining-elements, choice),
                 concatenate(result, list(choice)))
          end if
        end method sort;
  sort(constraints, elements, #())
end method topological-sort;
define method tie-breaker-rule (minimal-elements, cpl-so-far)
  block (return)
    for (cpl-constituent in cpl-so-far.reverse)
      let supers = cpl-constituent.direct-superclasses;
      let common = intersection(minimal-elements, supers);
      unless (empty?(common))
      end unless;
    end for
  end block
end method tie-breaker-rule;

Dylan Reference Manual - 17 OCT 1995
[Next] [Previous] [Up] [Top] [Contents] [Index]

Generated with Harlequin WebMaker