Search code examples
smalltalkpharo

A WeakIdentityKeyDictionary with no keys or values of size 1?


Try this script in Pharo:

dictionary := WeakIdentityKeyDictionary new.
key := Object new.
dictionary at: key put: 'hello'.
dictionary size. " --> 1 "
key := nil.
2 timesRepeat: [Smalltalk garbageCollect].

By now the dictionary should be empty. However:

dictionary keys isEmpty. " --> true"
dictionary values isEmpty. " --> true "

as expected, but

dictionary isEmpty. " --> false ??"
dictionary size. " --> 1 !! "

Solution

  • It seems to be like this by design. If you read the comments of the WeakKeyDictionary class (WeakIdentityKeyDictionary's superclass):

    I am a dictionary holding only weakly on my keys. This is a bit dangerous since at any time my keys can go away. Clients are responsible to register my instances by WeakArray such that the appropriate actions can be taken upon loss of any keys. As key may disappear at any time, my reported size may be greater than the number of keys encountered in iterations.

    (emphasis mine)

    The dictionary's internal array still has the association nil --> 'hello', and that's why the dictionary's size is 1, but WeakIdentityKeyDictionary's associationsDo: check for nil key's and avoid evaluating them (see the last line):

    associationsDo: aBlock 
        "Evaluate aBlock for each of the receiver's elements (key/value 
        associations)."
    
        super associationsDo: [:association | | key | 
            "Hold onto the key so it won't be collected while the block is evaluated."
            key := association key.
            key ifNotNil:[aBlock value: association]].
    

    Dictionary#associations is based on associationsDo:, so that's why dictionary associations is also empty.