The CLIM-SYS Package Contents Index Common Lisp Streams




33 Encapsulating Streams

An encapsulating stream is a special kind of stream that ``closes over'' another stream, handling some of the usual stream protocol operations itself, and delegating the remaining operations to the ``encapsulated'' stream. Encapsulating streams may be used by some CLIM implementations in order to facilitate the implementation of features that require the dynamic modification of a stream's state and operations. For example, accepting-values dialogs can be implemented by using an encapsulating stream that tailors calls to accept and prompt-for-accept in such a way that the output is captured and formatted into a dialog that contains prompts and fields that can be clicked on and modified by the user. Input editing can also be implemented using an encapsulating stream that manages the interaction between read-gesture and the input editing commands and rescanning. The form filling-output can be implemented by having an encapsulating stream that buffers output and inserts line breaks appropriately.

CLIM implementations need not use encapsulating streams at all. If encapsulating streams are used, they must adhere to the following protocols. Encapsulating streams are not part of CLIM's API.

33.1 Encapsulating Stream Classes

encapsulating-stream[Protocol Class]
The protocol class that corresponds to an encapsulating stream. If you want to create a new class that behaves like an encapsulating stream, it should be a subclass of encapsulating-stream. Subclasses of encapsulating-stream must obey the encapsulating stream protocol.Members of this class are mutable.
encapsulating-stream-pobject[Predicate]
Returns true if object is an encapsulating stream , otherwise returns false .

:stream[Init arg]
All encapsulating streams must handle the :stream initarg, which is used to specify the stream to be encapsulated.

standard-encapsulating-stream[Class]
This instantiable class provides a standard implementation of an encapsulating stream.

33.1.1 Encapsulating Stream Protocol

The standard-encapsulating-stream class must provide ``trampoline'' methods for all stream protocol operations. These ``trampolines'' will simply call the same generic function on the encapsulated stream. In particular, all of the generic functions in the following protocols must have trampolines.

The following generic function must also be implemented for all encapsulating stream classes.

encapsulating-stream-streamencapsulating-stream[Generic function]
Returns the stream encapsulated by the encapsulating stream encapsulating-stream .

33.1.2 The ``Delegation Problem''

The suggested implementation of encapsulating streams has a potential problem that we label the ``delegation'' or ``multiple self'' problem. Here is an example of the problem.

Suppose we implement accepting-values by using an encapsulating stream class called accepting-values-stream that will be used to close over an ordinary extended input and output stream. Let us examine two generic functions, stream-accept and prompt-for-accept . The stream-accept method on an ordinary stream calls prompt-for-accept . Now suppose that accepting-values-stream specializes prompt-for-accept . If we now create a stream of type accepting-values-stream (which we will designate A) which encapsulates an ordinary stream S, and then call stream-accept on the stream E, it will trampoline to stream-accept on the stream S. The desired behavior is for stream-accept to call the prompt-for-accept method on the stream E, but instead what happens is that the prompt-for-accept method on the stream S is called.

In order to side-step this problem without attempting to solve a difficult general problem in object-oriented programming, CLIM implementations may introduce a special variable, *original-stream* , which is bound by trampoline functions to the original encapsulating stream. Therefore, the stream-accept on the ordinary stream S will call prompt-for-accept on the value of (or *original-stream* stream ) . This idiom only needs to be used in places where one stream protocol function calls a second stream protocol function that some encapsulating stream specializes.

This ``solution'' does not solve the more general problem of multiple levels of encapsulation, but the complete stream protocol provided by CLIM should allow implementors to avoid using nested encapsulating streams.

*original-stream*[Variable]
This variable is bound by the trampoline methods on encapsulating streams to the encapsulating stream, before the operation is delegated to the underlying, encapsulated stream.



The CLIM-SYS Package Contents Index Common Lisp Streams