Mauricio Fernandez wrote:

> class WeakCache
>    attr_reader :cache
>    def initialize( cache = Hash.new )
>       @cache = cache
>    end
> 
>    def []( key )
>       value_id = @cache[key]
>       return ObjectSpace._id2ref(value_id) unless value_id.nil?
>       nil
>    end
> 
>    def make_lambda(key)
>      lambda{|value| @cache.delete(key) }
>    end
> 
>    def []=( key, value )
>       ObjectSpace.define_finalizer(value, make_lambda(key))
>       @cache[key] = value.object_id
>    end
> end
> 
> RUBY_VERSION                                       # => "1.8.4"
> RUBY_RELEASE_DATE                                  # => "2005-12-24"
> c = WeakCache.new
> puts c.cache.size
> 100000.times{|i| c[i] = i.to_s}
> GC.start
> puts c.cache.size
> __END__
> # >> 0
> # >> 3
> 
> 
> 
> That is very inefficient though, you want something more like
> 
> 
> class WeakCache
>    attr_reader :cache
>    def initialize( cache = Hash.new )
>       @cache = cache
>       @rev_cache = {}
>       @reclaim_method = method(:reclaim_value)
>    end
> 
>    def []( key )
>       value_id = @cache[key]
>       return ObjectSpace._id2ref(value_id) unless value_id.nil?
>       nil
>    end
> 
>    def reclaim_value(value_id)
>      @cache.delete @rev_cache[value_id]
>      @rev_cache.delete value_id
>    end
> 
>    def []=( key, value )
>       @rev_cache[value.object_id] = key
>       @cache[key] = value.object_id
>       ObjectSpace.define_finalizer(value, @reclaim_method)
>    end
> end
> 
> RUBY_VERSION                                       # => "1.8.4"
> RUBY_RELEASE_DATE                                  # => "2005-12-24"
> c = WeakCache.new
> puts c.cache.size
> 100000.times{|i| c[i] = i.to_s}
> GC.start
> puts c.cache.size
> __END__
> # >> 0
> # >> 4
> 
> 

I like your technique, but suppose the same value is stored for more 
than one key in a WeakCache?  When the value is finalized, only the last 
key will be removed from the cache.  I think it might be better to let 
the reverse cache hold more than one key per value.