fork()

Hisao Suzuki suzuki611 at okisoft.co.jp
Sun Jun 20 19:17:18 EDT 1999


In the view of some (or many?) Python programmers, to remove all
the references to an object is the obvious and deterministic way
to destroy the object.  The predictability of destructor
invocation favored by some (or many?) Pythoneers is based on
this rule.

She/he consciously writes codes to destroy the object based on
the rule.  Just the same, any C++ programmer consciously writes
`delete's to destroy the `new'ed object.  Both intents are very
similar to each other.  From _this_ point of view, what
"Tim Peters" <tim_one at email.msn.com> wrote
in article <000101beb886$628a1ea0$099e2299 at tim>:
> To me, that merely describes the conditions under which the respective
> languages treat an object as immortal today.  It makes good sense for
> Stroustrup to say that in C++ a garbage collector shouldn't invoke the
> finalizer for its flavor of immortal objects, but he's not arguing that
> position *because* they're immortal today, but instead because explictly
> new'ed objects never have their finalizer invoked in C++ unless explicitly
> delete'd, and GC is not explicit delete'tion.  

sounds too particular about superficial differences.  However,

> Python has no such rules, so
> the core of his argument doesn't apply to Python without more strain than I
> can swallow <0.9 wink>.

is certainly consistent and valid in the _official_ semantics
described in the Python Reference Manual.

At the same time, in the current Pytnon (or rather CPython), the
idea that to remove all references corresponds to the delete
operation in C++ (and thus being part of cycles in Python
corresponds to being never deleted in C++) is _also_ consistent.
And moreover, it is a valid working rule practically useful to
predict the object destruction.

I described it against what
Moshe Zadka <moshez at math.huji.ac.il> wrote in
article <Pine.SUN.3.95-heb-2.07.990611075346.4942G-100000 at sunset.ma.huji.ac.il>
< On Fri, 11 Jun 1999, Guido van Rossum wrote:
< <snip/>
< > ...this almost seems acceptable: in the formal semantics, objects
< > that are part of cycles would live forever, and as an invisible
< > optimization we recycle their memory anyway if we know they are
< > unreachable.  (I've got the feeling that I've seen this rule before
< > somewhere.)  
< <snip/>
< No, that can't be. If we did, it were in Scheme, and after you put it in,
< you'd be morally obliged to add full-fledged lambda, tail-recursion and 
< user visible continuations. 

There I said that Guido's idea is quite consistent and orthodox
in a sense which has almost nothing to do with Scheme.  If one
adopts the idea such as I described above, one can write rightly
working programs, can predict their behavior more precisely, and
might think well of Guido's idea (even if not definitively; it
is not the sole consequence even for C++, you know).

At the same time, if one adopts the _official_ weaker semantics
(which is also written by Guido), one can still (needless to
say!) write rightly working programs, and the above idea of
Guido would lose some power of persuasion (even if not
rejected).  To remove all the references _no_ longer means the
immediate destruction of the object.

All in all, each idea is a valid model for the current Python.
The definitive difference lies in the semantics of language it
relies on.  Regarding the favor of destruction predictability
such as seen in this newsgroup, the current actual semantics is
perhaps as important as the official one.

Nevertheless, please do not think that I stick to one idea.
Actually I have also a third idea, though it might be useless
for the purpose of storage reclamation (see article
<u36756gcoc.fsf at ares.sys1.ngo.okisoft.co.jp> on 03 Jun 1999
12:56:03 +0900).  I am not yet sure which one is better than
others in total ...


> Whose point <wink>?  Java has always guaranteed to "destroy objects in an
> order that ensures that the destructor for one object doesn't refer to an
> object that has been previously destroyed", and indeed "without help from
> the programmer".  So by "Java solved that one" I meant it satisfactorily
> addressed the points made in the quote.  That doesn't mean there aren't
> other points to be made, but since the quote you gave didn't make any other
> points I don't feel bad about commenting on the points it did make <wink>.

Even if the storage of such objects are not reclaimed yet, their
finalizer()s may have been already invoked.  This may be a real
problem for aggregation objects (if you once rely on finalizers
in Java).  Note that Stroustrup's "destroy" implies "call the
destructor".

The JLS says:
  "12.6.2 Finalizer Invocations are Not Ordered

   Java imposes no ordering on finalize method calls.  Finalizers
   may be called in any order, or even concurrently.

   As an example, if a circularly linked group of unfinalized
   objects becomes unreachable (or finalizer-reachable), then all
   the objects may become finalizable together.  Eventually, the
   finalizers for these objects may be invoked, in any order, or
   even concurrently using multiple threads.  If the automatic
   storage manager later finds that the objects are unreachable,
   then their storage can be reclaimed."

Therefore, the authors of the JLS continue:

  "It is straightforward to implement a Java class that will cause
   a set of finalizer-like methods to be invoked in a specified
   order for a set of objects when all the objects become
   unreachable.  Defining such a class is left as an exercise for
   the reader."

You see, to implement such a class needs _help_ from the
programmer.  It would be like the following.  It might be very
boring to write codes like this every time from the scratch, and
the component classes might lose flexibility and re-usability.

  public class HeadOfAggregation {
      int count;
      int expected_count;  ...
      protected void finalize() { trigger(); }
      public void trigger() {
          boolean r = false;
          synchronized (this) {
              count++;
              r = (count == expected_count);
          }
          if (r) finalize_aggregation_totally();
      }  ....
  }

  public class ComponentOfAggregation_1 { ....
      protected void finalize() { our_head.trigger(); }
  }

  public class ComponentOfAggregation_2 { ....
      protected void finalize() { our_head.trigger(); }
  }

--===-----========------------- Sana esprimo naskas sanan ideon.
SUZUKI Hisao            suzuki611 at okisoft.co.jp, suzuki at acm.org.




More information about the Python-list mailing list