Oops, I'm soooo stupid :) Instead, put the count in the finalization loop, and compare against it. e.g. finalizationProcess [true] whileTrue: [ WeakFinalizationList initTestPair. FinalizationSemaphore wait.
FinalizationCount := FinalizationCount + 1. FinalizationLock critical: [ WeakFinalizationList checkTestPair. FinalizationDependents do: [:weakDependent | weakDependent ifNotNil: [ [ weakDependent finalizeValues ] on: Exception fork: [:ex | ex pass ] ]]]].
finalizationCount ^FinalizationCount Set subclass: #WeakSet instanceVariableNames: 'flag finalizationCount' classVariableNames: '' poolDictionaries: '' category: 'Collections-Weak' size | newFinalizationCount | newFinalizationCount := WeakArray getFinalizationCount. newFinalizationCount == finalizationCount ifTrue: [^tally]. tally := self computeActualSIze. finalizationCount := newFinalizationCount On Fri, Jun 7, 2013 at 11:30 AM, Eliot Miranda <eliot.miranda@gmail.com>wrote:
On Fri, Jun 7, 2013 at 2:34 AM, Camille Teruel <camille.teruel@gmail.com>wrote:
On 7 juin 2013, at 11:19, Pharo Issue Tracker wrote:
A FogBugz case was edited by Stephane Ducasse.
Case ID: 10840 Title: WeakSet>>#size utterly broken Status: Resolved (Fix Review Needed) Category: Bug Project: Collection Area: Misc Priority: 3 - Must Fix Milestone: Pharo3.0: 30/03/2014 Assigned To: Camille Teruel
URL: https://pharo.fogbugz.com/f/cases/10840
Last message: Please can you send a mail to the mailing-list so that we all discuss this problems.
Hello everyone,
WeakSet>>#size is broken as demonstrated by the following snippet:
set := WeakSet new. set add: Object new. Smalltalk garbageCollect. set size. "answers 1 instead of 0"
That is because a WeakSet has no mean to know when its items get garbage collected, and thus the tally cannot be updated. So we need to override #size in Weak, I propose: size | counter | counter := 0. self do: [ :e | counter := counter + 1 ]. ^ counter But that it rather inefficient for such a simple query. Any proposition?
One way is to add WeakSets to FInalizationDependents and implement finalizeValues to update the size. But that's making work. A lazy solution might be better.
You *could*, I suppose, use the VM's count of the number of incremental and full GCs (alas there's no single count). I think this is too ugly and one would need something neater, but it would work like this:
size | newGCCount | newGCCount := self getGCCount. newGCCount == existingGCCount ifTrue: [^tally]. tally := self computeActualSIze. existingGCCount := newGCCount
where getGCCount ^(Smalltalk vmParameterAt: 7) + (Smalltalk vmParameterAt: 9)
There are obviously thread-safety issues here, but there are issues with the existing code and your suggestion too ;)
The most useful single count here would be a count that was incremented once in each GC that finalized one or more references.
Note also that for this to be reliable instances' record of the count would have to be invalidated on snapshot or start-up, which could entail an expensive allInstancesDo:.
Perhaps the class WeakSet should maintain its instances in (of course) a WeakSet and then add only itself to FinalizationDependents and enumerate the set on finalization?
I note that in the VisualWorks VM, objects that have references finalized are added to a queue so every instance that loses a reference gets sent finalize, instead of only dependents as in Squeak. This has its won problems (the VM must cope with a potentially large list) but I think it provides more convenient control.
The bug entry is: https://pharo.fogbugz.com/f/cases/10840
If you do not want to receive automatic notifications anymore, change your preferences in the Options screen. ( https://pharo.fogbugz.com/default.asp?pg=pgPrefs)
-- best, Eliot
-- best, Eliot