On Sun, Mar 21, 2021 at 3:35 PM Chris Angelico
On Mon, Mar 22, 2021 at 7:49 AM Ben Rudiak-Gould
wrote: In the "Object Lifetime" section you say "registers should be cleared
upon last reference". That isn't safe, since there can be hidden dependencies on side effects of __del__, e.g.:
process_objects = create_pipeline() output_process = process_objects[-1] return output_process.wait()
If the process class terminates the process in __del__ (PyQt5's QProcess
does), then implicitly deleting process_objects after the second line will break the code.
Hang on hang on hang on. After the second line, there are two references to the last object, and one to everything else. (If create_pipeline returns two objects, one for each end of the pipe, then there are two references to the second one, and one to the first.) Even if you dispose of process_objects itself on the basis that it's not used any more (which I would disagree with, since it's very difficult to manage that well), it shouldn't terminate the process, because one of the objects is definitely still alive.
In the hypothetical scenario, presumably create_pipeline() returns a list of process objects, where the process class somehow kills the process when it is finalized. In that case dropping the last reference to process_objects[0] would kill the first process in the pipeline. I don't know if that's good API design, but Ben states that PyQt5 does this, and it could stand in for any number of other APIs that legitimately destroy an external resource when the last reference is dropped. (E.g., stdlib temporary files.) Curiously, this is about the opposite problem that we would have if we were to replace the current reference counting scheme with some kind of traditional garbage collection system.
This is nothing to do with a register-based VM and everything to do with standard Python semantics, so this can't change.
Exactly. The link with a register-based VM is that if we replaced the value stack with temporary local variables (as the "register-based" VM scheme does), we'd have to decide on the lifetimes of those temporary variables. Finalizing them when the function returns might extend the lifetimes of some objects compared to the stack-based scheme. But finalizing all local variables (temporary or not) as soon as they are no longer needed by subsequent code could *shorten* the lifetimes, as in the above example. A reasonable solution would be to leave the lifetimes of explicitly named locals alone, but use the proposed ("as soon as possible") scheme for temporary variables. This would appear to match how values on the value stack are treated. Honestly that's how I read the quoted section of Skip's proto-PEP (since it explicitly mentions registers). A version of the example that exhibits the same questionable behavior would be this: return create_pipeline()[-1].wait() Presumably this would not work correctly with the PyQt5 process class. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...