[Python-Dev] iterzip()

Tim Peters tim.one@comcast.net
Tue, 30 Apr 2002 22:28:36 -0400


[Martin v. Loewis]
> ...
> However, the visit function could record this result. For example, for
> move_root_reachable:

I'm afraid it needs more knowledge than this, although it may be
surmountable.  A problem is that, e.g., tuples get tracked by GC immediately
after they're initialized in PyTuple_New(), and they're initialized to all
NULL slots.  So if gc happens to occur before a tuple T is filled in "for
real", traversing T isn't going to call visit_move (because T's slots are
still NULL).  This would cause gc to untrack T, even though T's creator may
eventually get around to making T part of a cycle.

> struct m_r_r{
>  PyGC_Head *reachable;
>  int immutable_nonnested;
> };
>
> static int
> visit_move(PyObject *op, struct m_r_r *tolist)
> {
>   if(PyObject_IS_GC(op)){
>      if(GC_is_tracked(op))
>        m_r_r->tolist.immutable_nonnested = 0;

I assume this was meant to be tolist->immutable_nonnested = 0.

>      ...
>   }
>   return 0;
> }
>
> static void
> move_root_reachable(PyGC_Head *reachable)
> {
>    struct m_r_r my_m_r_r;
>    my_m_r_r.reachable = reachable;

m_r_r.reachable isn't referenced elsewhere.

> 	for (; gc != reachable; gc=gc->gc.gc_next) {
> 		/* careful, reachable list is growing here */
> 		PyObject *op = FROM_GC(gc);
> 		traverse = op->ob_type->tp_traverse;
>                 my_m_r_r.immutable_nonnested = 1;
> 		(void) traverse(op,
> 			       (visitproc)visit_move,
> 			       (void *)reachable);
>                 if(my_m_r_r.immutable_nonnested
>                    && op->ob_type->tp_immutable(op)){

What the heck is tp_immutable()?  Are you implicitly assuming the existence
of a new typeslot function?  I'd be happy to special-case the snot out of
tuples, and leave it at that.  For that purpose, it may be enough just to
see whether a thing *is* a tuple, and all its slots are non-NULL and filled
with objects of the popular scalar immutable types (strings and numbers).

Hmm!  I bet we could go a long away leaving gc out of this entirely:
BUILD_TUPLE in ceval.c could check the types of the objects it stuffs into a
new tuple, and untrack it immediately then if it were safe to do so.  And
tupleconcat() could mindlessly inherit trackedness from the logical "or" of
its inputs' trackedness.  Would that get 80% of the potential benefit with
5% of the potential work?