Search code examples
smalltalkpharo

Pharo Smalltalk - How can I check if a message conforms to a protocol defined in another object's Class?


I'm looking at this form an Objective-C background so be gentle. The experiment looks like this:

Object1 has an instance variable named delegate.

Object1 receives a message and the proceeds to check if delegate implements a specific protocol (whose name is known beforehand), if it does, then it checks if the message is among the protocol's implemented methods. It then makes a decision on how to interact with the delegate and so on.

In Objective-C one has to define clear Protocols, usually stored in different files, and conforming to a protocol is checked by the compiler. In Pharo I can't seem to find how to check for this kind of information even though the Browser has a whole column dedicated to protocols, and beside grouping methods they seem to do very little.


Solution

  • Here are some few alternatives that could help you with this:

    1. Get the collection of all selectors that populate the object's class:
      • anObject class selectors
    2. Get the collection of all selectors that populate the object's class and all its superclasses:
      • anObject class allSelectors
    3. Ask the class whether it implements a given message (for its instances):
      • anObject class canUnderstand: #putTheSelectorHere
    4. Ask the object whether it understands a given message:
      • anObject respondsTo: #methodSelectorHere
    5. Use the MessageNotUnderstood mechanism:
      • (see explanation below)

    In 1 and 2 above you can use the returned collections to check whether they include a certain selector you are interested in. Features 3, 4 and 5 have a more dynamic nature. For example, you can refine the #doesNotUnderstand: method in your class as follows:

    MyClass >> #doesNotUnderstand: aMessage
        (delegate respondsTo: aMessage selector)
            ifTrue: [^delegate
               perform: aMessage selector
               withArguments: aMessage arguments].
        ^super doesNotUnderstand: aMessage
    

    This way, if your object receives a message that it does not understand, it will first receive the #doesNotUnderstand: message (without you having to do anything for this to happen) and here you could decide (e.g., by using the #respondsTo: message) whether to delegate it or not. If not, you can just relay on the default behavior (super doesNotUnderstand:) which would signal de MessageNotUnderstood exception.

    Of course, there is a 6th option, which would be for the sender of the message to handle the MNU exception, but I don't think this is what you are looking for here.