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