Skip to main content
Engineering LibreTexts

16.4: Classes, Method Dictionaries and Methods

  • Page ID
    39670
    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    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 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; a detailed edit history is available upon request.