Exercise 2: Checking a Real Python Reference Count — Possible Solution ==================================================================== THE CHECK ------------------------------ import sys vm, _ = compile_and_run(prog_gc) # this chapter's own makeAdder example garbage_objs = [o for o in vm.heap if o not in (vm.globals['keep'], vm.globals['keep'].upvalues[0], vm.globals['makeAdder'])] one_garbage = garbage_objs[0] refcount = sys.getrefcount(one_garbage) - 1 # -1 for getrefcount's own temp arg print(refcount) RESULT ------------------------------ refcount == 2 (approximately -- one from vm.heap itself, one from the local `garbage_objs` list this exercise's own code built to hold it; sys.getrefcount's own call adds one more, subtracted out above). The important fact isn't the exact number, which shifts with whatever else happens to be referencing the object at the moment of the check -- it's that the count is GREATER THAN ZERO, proving something is still holding a real reference. WHICH LINE IS RESPONSIBLE ------------------------------ def alloc_closure(self, function, upvalues): c = Closure(function, upvalues) self.heap.append(c) # <-- this line return c `self.heap.append(c)` is what keeps this object alive in Python's own terms. By the time this exercise's own code runs, nothing in the WISP PROGRAM references this particular adder closure anymore -- its own `makeAdder(20);` statement's return value was already popped by OP_POP the instant the call returned. If `self.heap` had never appended it in the first place, Python's own reference counting would have reclaimed it the moment OP_POP ran, exactly the way the chapter's own separate weakref demonstration confirmed for an ordinary Python object with no artificial tracking list holding it. WHY THIS WORKS AS AN ANSWER ------------------------------ This is the concrete, measured version of the chapter's own central twist: the collector isn't chasing a hypothetical problem. There is a real, non-zero, checkable Python reference count on an object the running Wisp program itself has completely finished with -- and that reference exists specifically because of a design decision this same chapter made (tracking every allocation in self.heap so there would be something for mark-and-sweep to sweep). The fix and the problem come from the same place.