FilterStreams prototype
Marcel Weiher
marcel at system.de
Sat Apr 3 13:22:14 UTC 1999
Hello Squeakers,
in an earlier message ( Musings about "ma" ) I mentioned a simple OO
pipe-and-filter implementation. I have now finally started porting
this stuff from Objective-C to Squeak. Do you think this is
worthwhile pursuing further or just another crazy idea? :-)
Motivation and Rationale
------------------------
The motivation for this package was the lack of reusability of
printing and other encoding tasks. The problem is that each method
taking part in an encoding task hard-codes the specific encoding
task, for example a collection receiving a #printOn: message sends
#printOn: to its elements.
The problem becomes apparent when trying to implement a #debugOn:
message that only differs from #printOn: for a couple of objects. At
first, this seems easy, defining #debugOn: as a rename of #printOn:
in Object, and implementing #debugOn: for those objects that should
behave differently, let's say Forms. However, this fails as soon as
there are nested objects to debug, for example a collection of Forms.
The collection receives the #debugOn: message, which is translated
to #printOn: and this in turn sends #printOn: to all the Forms, not
#debugOn: !
On an abstract level, this could be solved by adding 'subclassing'
of operations that works just like subclassing of objects with a
similar treatment of self (in this case, the current operation).
With the language as it is now, this feature can be simulated by
letting the stream argument that is constant in these operations also
carry the encoding message.
Overview
--------
The basic FilterStream interface is the #write: message to which it
responds by passing the argument of the #write: message to its target
using another #write: message. This makes FilterStreams composable
but doesn't actually accomplish anything.
To accomplish its processing, each FilterStream sends a processing
message to the objects it receives with itself as the argument,
expecting the object to write itself on the stream in an appropriate
encoding. Each FilterStream subclass defines its own processing
message. As a matter of fact the default action described above
(forwarding the argument to the target) is actually accomplished
indirectly using a filter message defined for Objects and basic
FilterStreams.
Status
------
This is the first prototype implementation. The basic skeleton is
there and there is an implementation of a PrintStream that could
replace #printOn:. Currently, it is implemented with a
#printOnStream: message paralleling the current implementation
because I am not quite ready for open-heart surgery yet... :-)
There is some code interfacing FilterStreams with the current
Streams and Collections, but that isn't fully thought out yet.
Using FilterStreams
-------------------
You get a filter stream by sending its class the 'stream' message.
You write any object(s) by sending: filter write:object.
You get its results by sending: result := filter contents.
Nesting:
You can nest FilterStreams using the #stream: creation message with
another FilterStream. #contents will be passed through to the final
FilterStream.
Defining new FilterStreams
--------------------------
- Subclass the FilterStream that matches your new functionality most
closely
- In your new FilterStream, implement a class method called
#filterSelector that defines the a single argument filterMessage your
filter will send.
- In class Object, (category 'filter streaming') implement the cover
method for your filterMessage. This simply send your superclass's
filterSelector.
- define an implementation of your filterMessage for every class you
want to behave differently for your FilterStream compared to your
FilterStream's superclass.
Important: when implementing your filterMessage, use #write: to
write subordinate objects to the stream, do not use the
filterMessage! This ensures that your method will be reusable by
future subclasses.
Applications
------------
All sorts of Byte-Encoding tasks, including #printOn:, #storeOn:,
HTML and XML encoding, argument marshalling etc. All these
operations could now share common code.
Other processing and encoding tasks. Morphic Canvases, for example,
would make a fine FilterStream, with the inherent double-dispatching
allowing both the Canvas and the graphical objects to react
specially. I've also implemented an HTML processing framework using
this technique.
Future Directions
-----------------
- Finish and polish the implementation.
- Replace current coding mechanisms with FilterStreams.
- Better integration with the current Streams mechanism.
- Implement read capabilities (co-routines and/or buffering)
- FilterStreams are really a special kind of reified operation. It
might be interesting to see what a generic facility for reified,
hierarchical operations would look like.
Marcel
Ôøº
More information about the Squeak-dev
mailing list
|