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

2

6

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.

Taffrail answered 6/9, 2015 at 11:16 Comment(2)
I don't know much about "protocols" in Objective-C, but you're right, in Smalltalk they're not much more than a way to group methods (a.k.a. "categories"). There are conventions about how to define these protocols, and which methods typically go in which protocol, but they're just, well, conventions. You can ask a class for #allMethodsInCategory:, but unless I'm misunderstanding you, I don't think that's what you're after, because it sounds like they're something entirely different in Objective-C. Leandro's answer gives you some options for checking which methods an object responds to.Ligurian
@AmosM.Carpenter That was exactly what I was looking for, found it myself while searching for something else. There was a method #allMethodsInCategory: that has been deprecated in Pharo 3.0 and later in favor of #allSelectorsInProtocol: which does what I want. See #2991466 Some other dialects have methodsInProtocol: all the same.Taffrail
A
7

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.

Amelita answered 6/9, 2015 at 18:49 Comment(4)
From what I see: #doesNotUnderstand is called after a method for the selector couldn't be found. So I would be getting the overhead of that with every message, and also I can't forward basic Object selectors, since both the redirector and the delegate are Objects and the redirector would only forward if it doesn't understand. Objective-C has forwardInvocation: which forwards absolutely everything even before method lookup takes place. Do we have that in Smalltalk?Taffrail
@unmircea I probably misunderstood your question. Perhaps you could edit it so to help us understand better what you are trying to do.Amelita
@LeandroCaniglia Managed to find the answer, there was a method allMethodsInCategory: that has been deprecated in Pharo 3.0 and later in favor of allSelectorsInProtocol: which does what I want. Add this to the answer and I'll accept it, it's very detailed so thank you! See here: #2991466 Some other dialects have methodsInProtocol: all the same.Taffrail
@StephanEggermont Good papers, Instance method wrappers seem to be a cool way to do what I want. Thank you! They were mentioned in a comment on an older question of mine and I managed to overlook them. #28226225Taffrail
P
3

There is the proxies work in Ghost/Marea and the original Smalltalk wrappers to the rescue I'm not sure the proxies have been updated for the latest Pharo version. Latest ghost version seems to be here

Passifloraceous answered 6/9, 2015 at 13:40 Comment(1)
Thanks for the fast response... I was looking for something more direct like the Obj-C [[myObject class] conformsToProtocol:@protocol(MyProtocol)]; that would be supported out of the box, something along the lines of myObject class conformsToProtocol:'Whatever'.Taffrail

© 2022 - 2024 — McMap. All rights reserved.