Search code examples
delegatessmalltalkpharo

Delegation in Pharo Smalltalk


What is the best way of doing delegation in Smalltalk, more specifically in Pharo? I know of the doesNotUnderstand strategy, but it does not delegates subclassResponsability messages.

I was thinking on something that delegates every message send not explicitly implemented on the class to some specified object, like I can do, for example, with @Delegate in Groovy. Is there some already known way of doing this?


Solution

  • doesNotUndersand: will only work on methods that the object does not understand (thus the name), so if you already have implemented a method it will not be used (as is the case with subclassResponsibility.

    If you use Pharo 5 (which should be released this week (May 2016)), you could use MetaLinks. It's a bit of an overkill, however what you are doing doesn't seem right to begin with (why would you want to delegate subclassResponsibility)?

    In either case, MetaLinks allow to attach runtime behavior to your methods, for example:

    You have some method that you want to delegate

    MyObject>>someMethod
        ^ self subclassResponsiblity
    

    And an object to which you wish to delegate to…

    MyObject>>delegate
        ^ delegate
    

    So you create a MetaLink

    link := MetaLink new
        metaObject: [ :object :selector :arguments |
            object delegate perform: selector withArguments: argument ];
        selector: #perform:withArguments:;
        arguments: #(object selector arguments);
        control: #instead.
    

    Which you can install to any method AST you want.

    (MyObject>>someMethod ast) link: link.
    

    Now every time the method will be called, instead (that's what the control: does) of executing the method, the arguments of the message (if any) will be given to the block in metaObject:.

    Although this should work and is extremely powerful mechanism, right now there are serious disadvantages that currently being addressed:

    • no documentation
    • little tooling support (it's pretty hard to debug)
    • a lot of work (we are working on a framework that would ease this as you would want to easily install them and uninstall them everywhere you need, but it's not ready yet, so it has to be done by hand)
    • recompilation removes the link (see point above)

    Summary

    To summarize, this is possible to do with MetaLinks as I've shown, however at the moment it's quite a lot of work, but we are addressing those issues.