Protocol dilution?

Marcel Weiher marcel at system.de
Tue Dec 22 21:57:23 UTC 1998


> Sorry for a belated response, but this composite wrapper scheme seems 
> cooler each time I look at it.

Thank you!  I am glad somebody out there likes it!

> (By the way, I'm not really that familiar with what the term  
"composite"
> means in a computer science/math sense... is it fair to say that a 
> "composite" is something that represents either one object or a
> collection
> of objects?)

The 'composite' part actually refers to the composite pattern that  
Peter Smet was working on and has nothing to do with my scheme, which  
doesn't really have a name yet.

[ Example:  2 collect raisedTo:#(1 to: 10) ]

> I was wondering exactly how this would be implemented... I guess "2 
> collect" would return a special Composite object?  This Composite  
object
> would then automatically forward any methods sent to it (e.g.  
raisedTo: )
> to its component object or collection, iterating if it's a  
collection.  No
> problem, I think.

That's pretty much it.  The implementation actually uses various  
types of streams in order to have a scheme that is very  
compositional.  These 'filter'-streams, modelled after UNIX filters,  
take another stream as input.  The ultimate source can be a stream  
over a collection, a single object (sometimes turned into an infinite  
repeater), or some sort of generator.  Maybe an object returning  
lines from a text file?

> But it sounds like it would take a look at the arguments passed  
along with
> the methods (e.g. (1 to: 20)) and determine if any of those are
> collections, and then iterate appropriately.  This part is trickier 
> now...
> what if a method normally has a collection as one of its  
arguments?  How
> would it know when to iterate, and when to simply pass the collection 
> along as a single argument?  For example:
>
> 2 collect addAll: (3 to: 10).
>
> I suppose you could just lay down the rule that all messages sent to 
> composites will have their collection arguments iterated through, so 
> you'd
> never want to send something like addAll: to a composite.  (Or, it  
might
> be safer to get rid of the collection-argument iterating altogether.)  

Yes, it probably is safer to do just that, and that's one of the  
variants I have examined.  This requires 'streaming' arguments to be  
explicitly converted:

    2 collect raisedTo:(2 to: 10) collect
or maybe
    2 collect raisedTo:(2 to: 10) each

Which variant is better is one of the questions that should be  
resolved, though I somewhat favor the explicit approach, even if it  
is a little more typing, because it is much more orthogonal and  
probably adheres better to the principle of least astonishment.

> Anyway, what I like about this scheme is that (in addition to handling 
> messages to single objects and collections) it can get rid of the  
need to
> always use blocks for simple iterations, simplifying a lot of code.  As 
> your example shows:
>
> arg1 do fire
>
> is a lot more concise (and probably more readable to a novice) than 
>
> arg1 do: [:each | each fire]
>
> I guess this only works where "each" is the first item after the  
vertical
> bar, but that's often the case for most iterations.

Not necessarily:

    arg1 do: [ :each | someOtherObject fire:each ]
turns into
    someOtherObject do fire: arg1 each

As you noted for the other examples, I think this is also somewhat  
more natural, because it preserves the original message:
    someOtherObject fire: arg1
and just adds a little embellishment that says 'send this message  
not just to a single object but to several'.  It's really a sort of  
multicast for Smalltalk messages, and it gets you thinking what other  
funky things could be done with messages/operations ...

> I wonder what the performace implications of this scheme would be... I 
> suppose creating a Composite object for every iteration might be a bad 
> thing, but maybe optimizable...

Currently, it is significantly slower than block-style iteration.  I  
haven't narrowed it down yet, but I think the major overhead is  
probably sending Message objects via 'sentTo:' instead of direct  
byte-coded messages.  There are several ways of making it fast again,  
the coolest probably using some sort of meta-level constructs.

Again, thanks for the feedback.  I am off on vacation now, so a  
happy holiday season to everyone and let's talk more in January.

Cheers,

Marcel





More information about the Squeak-dev mailing list