I was rummaging around in the Morphic stuff, and it is plain that there is going to be lots more pluggability in the interfaces.
The current Smalltalk idiom for such things is to specify a #symbol to perform the plugged in action.
Before alot more pluggable this and thats are made, I was wondering if it is worthwhile to consider changing the idiom, to instead pass in a block to evaluate as the standard way of doing pluggability?
There are pluses and minuses to doing this, here is my list (with some schizophrenic comments about my own list)
Blocks to evaluate are a good thing -----------------------------------
-There may be no need to make a method to handle the pluggablity action, you can do what you need right in the block.
-(For pluggable actions that need to be fast) it is easier to imagine tuning up methods that have real 'static' sends in the pluggable block, rather than some scheme that makes 'perform' run fast.
Objection: most pluggable things don't need to be fast. Yeah but: the pluggable action inside of things like sliders and drag 'n drop would benefit from being fast.
-It would easier to capture other data to pass into the pluggable block. The slider is an example, where the pluggable #symbol can be provided with a user defined argument array, in addition to the standard slider supplied argument.
-It would be easy and 'thin' to provide an interface that accepted the #symbol kind of pluggablity, by simply sticking the symbol in a block to evaluate and passing that to the block argument interface.
-This would be familiar to the Java crowd. (Don't throw rotten fruit at me, please)
-(This is a pretty opaque argument). Using a block is a better match of the moment in time when you know something to the moment in time you want to use what you know. That is, 'performing' something is a good match, when you don't know at the calling point what you want until just the instant before you do the perform; the passed in block matches the fact that you know what you want to do at the time that you write the method which calls for the opening of the pluggable action.
Objection: What did you just say?
Blocks to evaluate are a bad thing ----------------------------------
-Anonymous chunks of code are scary and hard to debug.
-The blocks will be hard to track down and revise, in the event they need to be changed; it is better to insist that they be in named methods
Comments?
Tom Morgan said:
I was rummaging around in the Morphic stuff, and it is plain that there is going to be lots more pluggability in the interfaces.
The current Smalltalk idiom for such things is to specify a #symbol to perform the plugged in action.
Before alot more pluggable this and thats are made, I was wondering if it is worthwhile to consider changing the idiom, to instead pass in a block to evaluate as the standard way of doing pluggability?
I've just been working with elisp and read some remarks about the relative value of using named vs anonymous functions for hooks, and it seems to me this is basically the same question. That is, what's the difference between a method and a block? The method has a selector stored in some method dictionary and the block doesn't. Evaluating the method, given the selector, involves a search for the associated block and then evaluating the block. So the block is probably faster. On the other hand since the block is anonymous it will probably need to be replicated if it needs to be plugged into several different slots, while the method simply has the selector duplicated. Furthermore, because of the way method identification is done, different classes can use the same selector with different implementations -- so the same "browser view" can be used by signifcantly different browsers by providing different methods for the same selector. That's probably the biggest argument for staying with selectors.
An alternative mechanism would be to have a Dictionary with blockNames as keys and blocks as values (very like a method dictionary?) the key goes to the pluggable... If one used Smalltalk, the system dictionary, the keys are then global -- the search is faster, but there's only one implementation. If one uses Class Pools, there's a different set of attributes.
Personally, I think I prefer the current implementation because of the ease of extending the system.
joe
At 6:58 AM -0700 5/28/98, Joe Davison wrote:
the block. So the block is probably faster. On the other hand since the block is anonymous it will probably need to be replicated if it needs to be plugged into several different slots,
I guess this is the best argument. Folks will probably replicate the block notation rather than write a single block and use it via variable everywhere, thereby using a lot more space.
while the method simply has the selector duplicated. Furthermore, because of the way method identification is done, different classes can use the same selector with different implementations -- so the same "browser view" can be used by signifcantly different browsers by providing different methods for the same selector. That's probably the biggest argument for staying with selectors.
If the block is passed the view as an argument it can just send the same selector to the view and acheive the same result. There is no difference.
--- james mccartney james@clyde.as.utexas.edu james@lcsaudio.com If you have a PowerMac check out SuperCollider, a real time synth program: http://www.audiosynth.com
Tom Morgan wrote:
I was rummaging around in the Morphic stuff, and it is plain that there is going to be lots more pluggability in the interfaces.
The current Smalltalk idiom for such things is to specify a #symbol to perform the plugged in action.
Before alot more pluggable this and thats are made, I was wondering if it is worthwhile to consider changing the idiom, to instead pass in a block to evaluate as the standard way of doing pluggability?
I'd like to put out another possibility. Rather than trying to decide should it be selector symbols or should it be blocks, why not use polymorphism to allow either?
Make it possible for the plug to be either a selector symbol to be performed, a message to be sent or a block to be performed. This could be accomplished either by overloading #perform: to do this, or creating a new selector for this purpose (perhaps something like #evaluate: ?) and then having that be used by all the invocations of pluggable behavior.
Using #evaluate: as an example, one could do something like:
Object >> evaluate: anEvaluatableObject ^ anEvaluatableObject evaluateWith: self
Symbol >> evaluateWith: receiver ^ receiver perform: self
BlockContext >> evaluateWith: argument ^ self numArgs = 1 ifTrue: [self value: argument] ifFalse: [self value]
Message >> evaluateWith: receiver ^ self sendTo: receiver
Using a new selector, like #evaluate:, would of course, necessitate changing all the places where pluggable actions are evoked. Alternatively, the above could be called from #perform:withArguments: rather than generating an error when the selector isn't a Symbol. I guess there are pros and cons to either way.
Comments on this approach to generalizing pluggable behavior?
------------------------------------------- Bill Dargel wdargel@shoshana.com Shoshana Technologies 100 West Joy Road, Ann Arbor, MI 48105 USA
squeak-dev@lists.squeakfoundation.org