Skip to main content
Engineering LibreTexts

11.6: Some Hints for Using Collections

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

    A common mistake with add: The following error is one of the most frequent Smalltalk mistakes.

    | collection |
    collection := OrderedCollection new add: 1; add: 2.
    collection
    >>> 2
    

    Here the variable collection does not hold the newly created collection but rather the last number added. This is because the method add: returns the element added and not the receiver.

    The following code yields the expected result:

    | collection |
    collection := OrderedCollection new.
    collection add: 1; add: 2.
    collection
    >>> an OrderedCollection(1 2)
    

    You can also use the message yourself to return the receiver of a cascade of messages:

    | collection |
    collection := OrderedCollection new add: 1; add: 2; yourself
    >>> an OrderedCollection(1 2)
    

    Removing an element of the collection you are iterating on Another mistake you may make is to remove an element from a collection you are currently iterating over.

    | range |
    range := (2 to: 20) asOrderedCollection.
    range do: [ :aNumber | aNumber isPrime
                            ifFalse: [ range remove: aNumber ] ].
    range
    >>> an OrderedCollection(2 3 5 7 9 11 13 15 17 19)
    

    This result is clearly incorrect since 9 and 15 should have been filtered out!

    The solution is to copy the collection before going over it.

    | range |
    range := (2 to: 20) asOrderedCollection.
    range copy do: [ :aNumber | aNumber isPrime
                                    ifFalse: [ range remove: aNumber ] ].
    range
    >>> an OrderedCollection(2 3 5 7 11 13 17 19)
    

    Redefining = but not hash A difficult error to spot is when you redefine = but not hash. The symptoms are that you will lose elements that you put in sets or other strange behaviour. One solution proposed by Kent Beck is to use bitXor: to redefine hash. Suppose that we want two books to be considered equal if their titles and authors are the same. Then we would redefine not only = but also hash as follows:

    Book >> = aBook
        self class = aBook class ifFalse: [ ^ false ].
        ^ title = aBook title and: [ authors = aBook authors ]
    
    Book >> hash
        ^ title hash bitXor: authors hash
    

    Another nasty problem arises if you use a mutable object, i.e., an object that can change its hash value over time, as an element of a Set or as a key to a Dictionary. Don’t do this unless you love debugging!


    This page titled 11.6: Some Hints for Using Collections 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.