| Overview of CLIM | Contents | Index | Regions |
2 Conventions
This chapter describes the conventions used in this specification and in the
CLIM software itself.
2.1 Audience, Goals, and Purpose
This document, the CLIM Release 2 Specification, is intended for vendors.
While it does define the Application Programmer's Interface (API), that is, the
functionality that a customer/consumer would use to write an application, it
also defines the names and functionality of some internal parts of CLIM. These
``portals'' in implementation space allow one vendor to extend, for example, the
output record mechanism and have it work with another vendor's implementation of
incremental redisplay. We have attempted to carefully identify the appropriate
``portals'' so that the API can be implemented efficiently, but we have also
tried not to overconstrain the specification so that it restricts creativity of
implementation or the possibility for extension. This also affects the more
sophisticated application writers who want to go a little below the published
API but still want portable applications. This document defines which
functionality is part of the advertised API, and which is part of the internal
protocols.
In this document, we refer to three different audiences. A CLIM user is a person who uses an application program that was written using CLIM. A CLIM programmer is a person who writes application programs using CLIM. A CLIM implementor is a programmer who implements CLIM or extends it in some non-trivial way.
2.2 Package Structure
CLIM defines a variety of packages in order to provide its functionality. In
general, no symbols except for the symbols in this specification should be added
to those packages.
The clim-lisp package is intended to implement as much of the draft X3J13 Common Lisp as possible, independent of the conformance of individual vendors. (When all Lisp vendors implement X3J13 Common Lisp, the clim-lisp package could be eliminated.) clim-lisp is the version of Common Lisp in which CLIM is implemented and which the clim-user package uses instead of common-lisp . clim-lisp contains only exported symbols, and is locked in those implementations that allow package locking.
clim is the package where the symbols specified in this specification live. It contains only exported symbols and is locked in those implementations that allow package locking.
clim-sys is the package where useful ``system-like'' functionality lives, including such things as resources and multi-processing primitives. It contains functionality that is not part of Common Lisp, but which is not conceptually the province of CLIM itself. It contains only exported symbols and is locked in those implementations that allow package locking.
No code is written in any of the above packages, but rather code is written for symbols in the above packages. None of the above use any other packages (in the sense of the :use option to defpackage ). A CLIM implementation might define a clim-internals package that uses each of the above packages, thus getting the definition of Lisp from clim-lisp . It would then implement the functionality of the symbols in clim and clim-sys in the clim-internals package.
clim-user is a package that programmers can use if they don't wish to create their own package. It is the CLIM analog of common-lisp-user .
2.3 ``Spread'' Point Arguments to Functions
Many functions that take point arguments come in two forms: structured and spread . Functions that take structured point arguments take the
argument as a single point object. Functions that take spread point
arguments take a pair of arguments that correspond to the x and y
coordinates of the point.
Functions that take spread point arguments, or return spread point values have an asterisk in their name, for example, draw-line* .
2.4 Immutability of Objects
Most CLIM objects are immutable , that is, at the protocol level none
of their components can be modified once the object is created. Examples of
immutable objects include all of the members of the region classes, colors
and opacities, text styles, and line styles. Since immutable objects by
definition never change, functions in the CLIM API can safely capture immutable
objects without first copying them. This also allows CLIM to cache immutable
objects. Constructor functions that return immutable objects are free to either
create and return a new object, or return an already existing object.
A few CLIM objects are mutable . Examples of mutable objects include streams and output records. Some components of mutable objects can be modified once the object has been created, usually via setf accessors.
In CLIM, object immutability is maintained at the class level. Throughout this specification, the immutability or mutability of a class will be explicitly specified.
Some immutable classes also allow interning . A class is said to be interning if it guarantees that two instances that are equivalent will always be eq . For example, if the class color were interning, calling make-rgb-color twice with the same arguments would return eq values. CLIM does not specify that any class is interning, however all immutable classes are allowed to be interning at the discretion of the implementation.
In some rare cases, CLIM will modify objects that are members of immutable classes. Such objects are referred to as being volatile . Extreme care must be take with volatile objects. This specification will note whenever some object that is part of the API is volatile.
2.4.1 Behavior of Interfaces
In this specification, any interfaces that take or return mutable objects can
be classified in a few different ways.
Most functions do not capture their mutable input objects, that is, these functions will either not store the objects at all, or will copy any mutable objects before storing them, or perhaps store only some of the components of the objects. Later modifications to those objects will not affect the internal state of CLIM.
Some functions may capture their mutable input objects. That is, it is unspecified as to whether a CLIM implementation will or will not capture the mutable inputs to some function. For such functions, programmers should assume that these objects will be captured and must not modify these objects capriciously. Furthermore, it is unspecifed what will happen if these objects are later modified.
Some programmers might choose to create a mutable subclass of an immutable class. If CLIM captures an object that is a member of such a class, it is unspecified what will happen if the programmer later modifies that object. If a programmer passes such an object to a CLIM function that may capture its inputs, he is responsible for either first copying the object or ensuring that the object does not change later.
Some functions that return mutable objects are guaranteed to create fresh outputs . These objects can be modified without affecting the internal state of CLIM.
Functions that return mutable objects that are not fresh objects fall into two categories: those that return read-only state , and those that return read-write state . If a function returns read-only state, programmers must not modify that object; doing so might corrupt the state of CLIM. If a function returns read/write state, the modification of that object is part of CLIM's interface, and programmers are free to modify the object in ways that ``make sense''.
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.
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:
(defclass 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.(defun presentationp (object) (typep object 'presentation))
CLIM always provides at least one ``standard'' instantiable class that implements each protocol.
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:
(defgeneric extended-input-stream-p (object))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.(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)))
2.6 Specialized Arguments to Generic Functions
Unless otherwise stated, this specification uses the following convention
for specifying which arguments to generic functions are specialized:
For example, the modifying function for output-record-position might be called in either of the following two ways:
(setf (output-record-position record) (values nx ny))The second form works because output-record-position itself returns two values.(setf (output-record-position record1) (output-record-position record2))
Some CLIM implementations may not support setf* due to restrictions imposed by the underlying Lisp implementation. In this case, programmers may use special ``setter'' function instead. In the above example, output-record-set-position is the ``setter'' function.
2.8 Sheet, Stream, or Medium Arguments to Macros
There are many macros that take a sheet, stream, or medium as one of the
arguments, for example, with-new-output-record and formatting-table .
In CLIM, this argument must be a variable bound to a sheet, stream, or medium;
it may not be an arbitrary form that evaluates to a sheet, stream, or medium.
t and sometimes nil are usually allowed as special cases; this causes
the variable to be interpreted as a reference to another stream variable
(usually *standard-output* for output macros, or *standard-input* for
input macros). Note that, while the variable outside the macro form and the
variable inside the body share the same name, they cannot be assumed to be the
same reference. That is, the macro is free to create a new binding for the
variable. Thus, the following code fragment will not necessarily affect the
value of stream outside the formatting-table form:
(formatting-table (stream) (setq stream some-other-stream) ...)Furthermore, for the macros that take a sheet, stream, or medium argument, the position of that variable is always before any forms or other ``inputs''.
2.9 Macros that Expand into Calls to Advertised Functions
Some macros that take a ``body'' argument expand into a call to an advertised
function that takes a functional argument. This functional argument will
execute the suppled body. For a macro named ``with- environment'',
the function is generally named ``invoke-with- environment''. For
example, with-drawing-options might be defined as follows:
(defgeneric invoke-with-drawing-options (medium continuation &key) (declare (dynamic-extent continuation)))(defmacro with-drawing-options ((medium &rest drawing-options) &body body) `(flet ((with-drawing-options-body (,medium) ,@body)) (declare (dynamic-extent #'with-drawing-options-body)) (invoke-with-drawing-options ,medium #'with-drawing-options-body ,@drawing-options)))
(defmethod invoke-with-drawing-options ((medium clx-display-medium) continuation &rest drawing-options) (with-drawing-options-merged-into-medium (medium drawing-options) (funcall continuation medium)))
When this specification says that ``an error is signalled'' in some situation, this means that:
| Overview of CLIM | Contents | Index | Regions |