Great! A cross-post with c.l.s. I started to respond there, but I find the mailing list here homier...
I just wanted to add some comments to Tim's approach. It is a good approach, and one that I've used before.
A) He uses a single delegate. One could imagine having multiple delegates, with some sort of conflict resolution mechanism.
B) The delegate is static. If the interface of delegate changes (by any of a number of means, not the least of which is putting a different object in the 'delegate' slot) then the 'cache' of CompiledMethods may no longer be valid.
C) If the receiver is used as a delegate, #canUnderstand: must be over-ridden to search for an applicable delegation path, otherwise the receiver will appear to refuse to respond to a message that it actually would (through the reciever's delegate)
D) He classifies the method under 'auto-delegate'. It is nice to know when you are over-ridding a 'programmatically' created method. This is just a specific instance of: 'It would be nice if the Browser warned when you change a method in a category different from the one you are browsing.'
E) Although not relevent for Squeak (except for optimization), The Compiler may not be availiable at runtime. It is still possible To "fake" the compiler by creating methods methods by just piecing together the needed byte codes for methods of that form.
-- Mike Klein
Hi, all:
Here's a cute trick / crufty hack I recently posted to comp.lang.smalltalk. It was in regards to someone complaining that they had to recreate a bunch of methods when using a delegate to implement multiple-inheritance-like operation. Instead of manually doing this (painful) or dynamically doing this by implementing doesNotUnderstand: (slow), why not combine the two and have the doesNotUnderstand: method install the custom-created method?
Comments?
| I see. The basic Implementation pattern if I remember correctly. I guess | I'm just looking for something better. If I've got 20 methods in the | implementation or "add-in" class, why should I have to write 20 new methods | that simply say: | | doSomething | | ^otherClass doSomething | | The extra effort is bad enough, but the unacceptable part for my is that | I now have to write code in several places -- each time I add or change a | mehod in the implementation class, I have to add/change the methods in all | the other classes that use it.
Ah, but you don't have to write the code -- why not have the system do it for you? Just implement a doesNotUnderstand: method that installs the named method to reflect it to the "delegate" object (inspired by the "auto-accessor" facility of Squeak):
doesNotUnderstand: aMessage
| selector keywords selString | selector := aMessage selector. (delegate class canUnderstand: selector) ifTrue: [keywords := selector findTokens: ':'. selector isInfix ifTrue: [selString := keywords first , ' t1'] ifFalse: [selector isKeyword ifTrue: [selString := ''. 1 to: keywords size do: [:i | selString := selString , ' ', (keywords at: i) , ': t', i printString]] ifFalse: [selString := keywords first]]. self class compile: selString , ' ^ delegate ' , selString classified: 'auto-delegate'. ^ delegate perform: selector with: aMessage arguments] ifFalse: [^ super doesNotUnderstand: aMessage]
-- tim
squeak-dev@lists.squeakfoundation.org