One problem with wrapper streams is the need for a wrapper stream to intercept methods invoked by its inner stream. For example, consider two hypothetical streams, <interactive-stream> and <dialog-stream>, the latter a subclass of <wrapper-stream>. Both of these classes have a method called prompt. The <interactive-stream> class specializes read thus:
define method read (s :: <interactive-stream>,
n :: <integer>,
#key on-end-of-stream);
prompt(s);
next-method()
end method;
If a <dialog-stream> is used to wrap an <interactive-stream> then an invocation of read on the <dialog-stream> will call prompt on the inner <interactive-stream>, not on the <dialog-stream>, as desired. The problem is that the <dialog-stream> delegates some tasks to its inner stream, but handles some other tasks itself.
Delegation by inner-streams to outer-streams is implemented by the use of the outer-stream function. The outer-stream function is used instead of the stream itself whenever a stream invokes one of its other protocol methods.
A correct implementation of the read method in the example above would be as follows:
define method read (stream :: <interactive-stream>,
n :: <integer>,
#key on-end-of-stream)
prompt(s.outer-stream);
next-method()
end method;
The initialize method on <stream> is defined to set the outer-stream slot to be the stream itself. The initialize method on <wrapper-stream> is specialized to set the outer-stream slot to be the "parent" stream:
define method initialize (stream :: <wrapper-stream>,
#key on, #rest all-keys);
an-inner-stream.outer-stream := stream;
next-method()
end method;