16.4: Classes, Method Dictionaries and Methods

Pharo by Example 5.0 · LibreTexts

0%

Contents

    Text

    Size
    100%
    Theme
    Typeface
    Line length
    Spacing

    From LibreTexts, under CC BY-SA 3.0, as the source states it; its equations are written in TeX, which the PDF shows typeset. This page at LibreTexts.

    16.4: Classes, Method Dictionaries and Methods

    Since classes are objects, we can inspect or explore them just like any other object.

    Evaluate Point inspect.

    In Figure \(\PageIndex{1}\), the inspector shows the structure of class Point. You can see that the class stores its methods in a dictionary, indexing them by their selector. The selector #* points to the decompiled bytecode of Point>>*.

    Inspector on class Point and the bytecode of its #* method.
    Figure \(\PageIndex{1}\): Inspector on class Point and the bytecode of its #* method.

    Let us consider the relationship between classes and methods. In Figure \(\PageIndex{2}\) we see that classes and metaclasses have the common superclass Behavior. This is where new is defined, amongst other key methods for classes. Every class has a method dictionary, which maps method selectors to compiled methods. Each compiled method knows the class in which it is installed. In Figure \(\PageIndex{1}\) we can even see that this is stored in an association in literal6.

    Classes, method dictionaries and compiled methods.
    Figure \(\PageIndex{2}\): Classes, method dictionaries and compiled methods.

    We can exploit the relationships between classes and methods to pose queries about the system. For example, to discover which methods are newly introduced in a given class, i.e., do not override superclass methods, we can navigate from the class to the method dictionary as follows:

    [:aClass| aClass methodDict keys select: [:aMethod |
        (aClass superclass canUnderstand: aMethod) not ]] value: SmallInteger
    >>> an IdentitySet(#threeDigitName #printStringBase:nDigits: ...)
    

    A compiled method does not simply store the bytecode of a method. It is also an object that provides numerous useful methods for querying the system. One such method is isAbstract (which tells if the method sends subclassResponsibility). We can use it to identify all the abstract methods of an abstract class.

    [:aClass| aClass methodDict keys select: [:aMethod |
        (aClass>>aMethod) isAbstract ]] value: Number
    >>> an IdentitySet(#storeOn:base: #printOn:base: #+ #- #* #/ ...)
    

    Note that this code sends the >> message to a class to obtain the compiled method for a given selector.

    To browse the super-sends within a given hierarchy, for example within the Collections hierarchy, we can pose a more sophisticated query:

    class := Collection.
    SystemNavigation default
        browseMessageList: (class withAllSubclasses gather: [:each |
            each methodDict associations
                select: [:assoc | assoc value sendsToSuper]
                thenCollect: [:assoc | RGMethodDefinition realClass: each
                    selector: assoc key]])
        name: 'Supersends of ', class name, ' and its subclasses'
    

    Note how we navigate from classes to method dictionaries to compiled methods to identify the methods we are interested in. A RGMethodDefinition is a lightweight proxy for a compiled method that is used by many tools. There is a convenience method CompiledMethod>>methodReference to return the method reference for a compiled method.

    (Object>>#=) methodReference selector
    >>> #=
    

    This page titled 16.4: Classes, Method Dictionaries and Methods was last modified on Sat, 19 Dec 2020 08:13:43 GMT and is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by via source content that was edited to the style and standards of the LibreTexts platform.