Reputation: 535
how can I get a list of all the methods an object can understand?
for example:
set := 8 getAllMethods
will give me all methods 8
can understand in set
Upvotes: 1
Views: 847
Reputation: 3141
In code you can use allSelectors
:
set := 8 class allSelectors
gives you a set of all the names of messages (a. k. a. selectors) that 8 can understand.
If you need the CompiledMethods instead of only the message names, you can use lookupSelector:
| class |
class := 8 class. "will be SmallInteger"
set := class allSelectors collect: [:each | class lookupSelector: each]
If you don't want to do this in code but rather find out in the IDE which messages an object can understand, then I propose to use the protocols browser (a. k. a. Lexicon tool). You can open it via "browse protocol" from the context menu of a class:
I used it to find allSelectors and lookupSelector:, which are inherited from Behavior and not defined in Class itself.
Upvotes: 6
Reputation: 14858
This is interesting because of the following. At first glance one might be tempted to consider an expression like this one
anObject class withAllSuperclasses gather: [:class | class methodDictionary]
which gathers all the methods implemented in the class and its superclasses. However, if a method is defined in a class and in one of its superclasses, we should ignore the latter because anObject
will use the one in the class.
To remedy this side-effect of the above script we need to gather only the methods that are defined in the class which is closer to anObject class
. One way to do this is to enumerate the classes from top to bottom, adding all their methods to a Dictionary
. Since the dictionary will only retain the last element added to a given key
(in this case a selector
), only the ones that belong in the protocol of anObject
will survive:
methods := Dictionary new.
anObject class withAllSuperclasses reverseDo: [:class |
methods addAll: class methodDictionary associations].
Note the use of reverseDo:
for enumerating the classes downwards.
Another approach would be to enumerate the classes from bottom to top, checking whether the selector has already been visited:
methods := Dictionary new.
anObject class withAllSuperclasses do: [:class |
class methodDictionary do: [:cm |
methods at: cm selector ifAbsentPut: [cm]]]
(were cm
stands for CompiledMethod
)
The second version is a bit longer, more complex (it has two loops, one nested inside the other) and needs conditional logic (#at:ifAbsentPut:
). In other words, it shouldn't be the one chosen.
Note
When looking for ways to create a collection (in this case the collection of all methods understood by an object), first make sure you really need such a collection. For instance, you will need the collection if you want to display it on the screen. However, if you are only going to use the collection for membership checking, there might be other ways to proceed. In your case, you could simply ask the object:
anObject respondsTo: <selector>
and in case the answer is true
, recover the method using
anObject class lookupSelector: <selector>.
This is both simpler and more efficient because it doesn't create collections, etc.
Upvotes: 1