The Question Mark - blog by Mark Volkmann

Reflection

Overview

Smalltalk provides many methods for getting information about classes and objects. The following table lists some of them.

MethodAnswers
object classthe class of object
object instVarNamed: #varNamethe value of an instance variable in object
object instVarNamed: #varName put: newValuesets value of an instance variable in object and answers new value
object class = SomeClassanswers Boolean indicating if object is an instance of the class SomeClass (not one of its subclasses)
object isKindOf: SomeClassanswers Boolean indicating if object is an instance of the class SomeClass or one of its subclasses
object respondsTo: #selectoranswers Boolean indicating if the object responds to a given method selector
SomeClass namethe name of the class as a String
Smalltalk allClassesan Array of all classes defined in the current image
Smalltalk allClassesImplementing: #selectoran Array of all classes that implement a given selector
SystemOrganization categoryOfElement: #SomeClassname of the class category to which a given class belongs
SomeClass allClassVarNamesa Set of class variable names defined in this class
SomeClass allSelectorsan IdentitySet of all message selectors (as Symbol objects) supported by this class, including selectors in superclasses
SomeClass lookupSelector: #selectorthe matching CompiledMethod, indicating where it is found
SomeClass allInstancesan Array of all existing instances of this class
SomeClass allInstVarNamesan Array of instance variable names defined in this class
SomeClass allInstVarNamesEverywherean Array of instance variable names defined in this class and inherited classes
SomeClass allMethodsInCategory: 'some-category'an Array of instance methods in a given category, including those defined in this class and inherited
SomeClass allSubclassesan OrderedCollection of subclasses
SomeClass superclassa Class that is the superclass of this class
SomeClass withAllSuperclassesan OrderedCollection containing all superclasses of this class going up the hierarchy
SomeClass allSuperclassesan OrderedCollection of superclasses
SomeClass selectorsan Array of all instance method selectors (as Symbol objects) of this class
SomeClass classthe Metaclass subclass of this class
SomeClass class selectorsan Array of all class method selectors (as Symbol objects) of this class
SomeClass class allMethodsInCategory: 'some-category'an Array of class methods in a given category, including those defined in this class and inherited
CodeListPackages installedPackagesan Array of CodePackage objects (appear in System Browser class category pane)
thisContext sendera MethodContext describing the method that invoked the current one
someMethodContext receiverthe object that sent the message that invoked the MethodContext
someMethodContext selectorthe selector Symbol of the message that invoked the MethodContext
someSelector keywordsan Array of the keywords in the selector

Getting Keywords from Selectors

The following examples demonstrate getting keywords from a message selector:

#foo keywords. "#('foo')"
#foo:bar:baz: keywords. "#('foo:' 'bar:' 'baz:')"

Operating on All Instances

To run code on every instance of a given class, send the allInstancesDo: message to the class.

For example, to delete all instances of a given class, run SomeClass allInstancesDo: [:obj | obj delete].

Sending Messages

See the “Dynamic Messages” section in the “Messages” page. This describes how to use perform: to send messages to objects where the selector is a Symbol.

Finding the Method for a Selector

There isn’t a provided method that finds the nearest class in the inheritance hierarchy that implements a method with a given selector. I added the following method to do that. It is in the Behavior class in the method category “*TypeCheck”, so it is saved in the TypeCheck package.

lookupClassImplementingSelector: selectorSymbol
    "Look up the given selector in my methodDictionary.
    Return the class that implements it if found.
    Otherwise chase the superclass chain and try again.
    Return nil if no implementing class is found."
    | class |

    class := self.
    [class == nil] whileFalse: [
        class includesSelector: selectorSymbol :: ifTrue: [^ class].
        class := class superclass
    ].
    ^ nil

Finding Methods by Example

The Squeak development environment provides a way to find methods by example using the “Method Finder” tool (a.k.a. Selector Browser).

Squeak Selector Browser

I implemented similar functionality in Cuis, minus the GUI. See Cuis-Smalltalk-FindByExample. It’s amazing how fast this is!

Cuis Smalltalk Method Finder

For example, evaluating the following in a Workspace:

Finder methodsByExample: #(#(1 2 3 4) 2.5)

prints the following in the Transcript:

The following methods on #(1 2 3 4) with no arguments return 2.5:
- average
- mean

There are more examples in the README.

Questions

TODO: Why does allClassVarNames return a Set when allInstVarNames returns an Array? TODO: Is there a way to get all the message categories used by a class?