Skip to main content
Engineering LibreTexts

16.3: Browsing Code

  • Page ID
    39669
    \( \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}}\)

    In Pharo, everything is an object. In particular, classes are objects that provide useful features for navigating through their instances. Most of the messages we will look at now are implemented in Behavior, so they are understood by all classes.

    For example, you can obtain a random instance of a given class by sending it the message someInstance.

    Point someInstance
    >>> 0@0
    

    You can also gather all the instances with allInstances, or the number of active instances in memory with instanceCount.

    ByteString allInstances
    >>> #('collection' 'position' ...)
    
    ByteString instanceCount
    >>> 104565
    
    String allSubInstances size
    >>> 101675
    

    These features can be very useful when debugging an application, because you can ask a class to enumerate those of its methods exhibiting specific properties. Here are some more interesting and useful methods for code discovery through reflection.

    whichSelectorsAccess: returns the list of all selectors of methods that read or write the instance variable named by the argument

    whichSelectorsStoreInto: returns the selectors of methods that modify the value of an instance variable

    whichSelectorsReferTo: returns the selectors of methods that send a given message

    Point whichSelectorsAccess: 'x'
    >>> #(#degrees #grid: #roundTo: #nearestPointAlongLineFrom:to: ...)
    
    Point whichSelectorsStoreInto: 'x'
    >>> #(#bitShiftPoint: #setR:degrees: #setX:setY: #fromSton:)
    
    Point whichSelectorsReferTo: #+
    >>> an OrderedCollection(#degrees #reflectedAbout: #grid: ...)
    

    The following messages take inheritance into account:

    whichClassIncludesSelector: returns the superclass that implements the given message

    unreferencedInstanceVariables: returns the list of instance variables that are neither used in the receiver class nor any of its subclasses

    Rectangle whichClassIncludesSelector: #inspect
    >>> Object
    
    Rectangle unreferencedInstanceVariables
    >>> #()
    

    SystemNavigation is a facade that supports various useful methods for querying and browsing the source code of the system. SystemNavigation default returns an instance you can use to navigate the system. For example:

    SystemNavigation default allClassesImplementing: #yourself
    >>> {Object}
    

    The following messages should also be self-explanatory:

    SystemNavigation default allSentMessages size
    >>>370
    
    (SystemNavigation default allUnsentMessagesIn: Object selectors) size
    >>> 31
    
    SystemNavigation default allUnimplementedCalls size
    >>> 521
    

    Note that messages implemented but not sent are not necessarily useless, since they may be sent implicitly (e.g., using perform:). Messages sent but not implemented, however, are more problematic, because the methods sending these messages will fail at runtime. They may be a sign of unfinished implementation, obsolete APIs, or missing libraries.

    Point allCallsOn returns all messages sent explicitly to Point as a receiver.

    All these features are integrated into the programming environment of Pharo, in particular the code browsers. As we mentioned before, there are convenient keyboard shortcuts for browsing all implementors (CMD-b CMD-m) and browsing senders (CMD-b CMD-n) of a given message. What is perhaps not so well known is that there are many such pre-packaged queries implemented as methods of the SystemNavigation class in the browsing protocol. For example, you can programmatically browse all implementors of the message ifTrue: by evaluating:

    SystemNavigation default browseAllImplementorsOf: #ifTrue:
    
    Implementors of ifTrue.
    Figure \(\PageIndex{1}\): Browse all implementations of ifTrue:.

    Particularly useful are the methods browseAllSelect: and browseMethodsWithSourceString:matchCase:. Here are two different ways to browse all methods in the system that perform super sends (the first way is rather brute force, the second way is better and eliminates some false positives):

    SystemNavigation default browseMethodsWithSourceString: 'super'
        matchCase: true.
    SystemNavigation default browseAllSelect: [:method | method
        sendsToSuper ].
    

    This page titled 16.3: Browsing Code 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.