2.5 Protocol Classes and Predicates

CLIM supplies a set of predicates that can be called on an object to determine whether or not that object satisfies a certain protocol. These predicates can be implemented in one of two ways. [annotate]

The first way is that a class implementing a particular protocol will inherit from a protocol class that corresponds to that protocol. A protocol class is an "abstract" class with no slots and no methods (except perhaps for some default methods), and exists only to indicate that some subclass obeys the protocol. In the case when a class inherits from a protocol class, the predicate could be implemented using typep. All of the CLIM region, design, sheet, and output record classes use this convention. For example, the presentation protocol class and predicate could be implemented in this way: [annotate]

(defclass presentation () ())

(defun presentationp (object)
  (typep object 'presentation))

Note that in some implementations, it may be more efficient not to use typep, and instead use a generic function for the predicate. However, simply implementing a method for the predicate that returns true is not necessarily enough to assert that a class supports that protocol; the class must include the protocol class as a superclass. [annotate]

CLIM always provides at least one "standard" instantiable class that implements each protocol. [annotate]

The second way is that a class implementing a particular protocol must simply implement a method for a predicate generic function that returns true if and only if that class supports the protocol (otherwise, it returns false). Most of the CLIM stream classes use this convention. Protocol classes are not used in these cases because, as in the case of some of the stream classes, the underlying Lisp implementation may not be arranged so as to permit it. For example, the extended input stream protocol might be implemented in this way: [annotate]

(defgeneric extended-input-stream-p (object))

(defmethod extended-input-stream-p ((object t)) nil)

(defmethod extended-input-stream-p ((object basic-extended-input-protocol)) t)

(defmethod extended-input-stream-p
           ((encapsulating-stream standard-encapsulating-stream))
  (with-slots (stream) encapsulating-stream
    (extended-input-stream-p stream)))

Whenever a class inherits from a protocol class or returns true from the protocol predicate, the class must implement methods for all of the generic functions that make up the protocol. [annotate]