Skip to main content
Engineering LibreTexts

9.6: Some Hints for Using Collections

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

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

    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 := 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 := 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. remove:

    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 := (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 both = and 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 xor: 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:

    Code \(\PageIndex{1}\) (Squeak): Redefining = and hash.

    Book»= aBook
        self class = aBook class ifFalse: [↑ false].
        ↑ title = aBook title and: [ authors = aBook authors]
    
    Book»hash
        ↑ title hash xor: 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 9.6: Some Hints for Using Collections is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Andrew P. Black, Stéphane Ducasse, Oscar Nierstrasz, Damien Pollet via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.