RFC: Proposal: Deterministic Object Destruction

Paul Moore p.f.moore at gmail.com
Fri Mar 2 10:36:58 EST 2018


On 2 March 2018 at 15:09,  <ooomzay at gmail.com> wrote:
> We must be discussing a different RAII. That is the raison d'etre of RAII: RAII directly addresses this problem in an exception-safe way that does not burden the resource user at all.

RAII works in C++ (where it was initially invented) because it's used
with stack-allocated variables that have clearly-defined and limited
scope. In my experience writing C++, nobody uses RAII with
heap-allocated variables - those require explicit allocation and
deallocation and so are equivalent to having an explicit "close()"
method in Python (or using __del__ in CPython as it currently exists).

Python doesn't have stack allocation, nor does it have a deterministic
order of deletion of objects when their last reference goes out of
scope (which can happen simultaneously for many objects):

class Tracker:
    def __init__(self, n):
        self.n = n
    def __del__(self):
        print("Deleting instance", self.n)

def f():
    a = Tracker(1)
    b = Tracker(2)

f()

The language doesn't guarantee that a is removed before b. Are you
proposing to make that change to the language as well?

Also Python only has function scope, so variables local to a
smaller-than-the-function block of code aren't possible. That's
something that is used in C++ a lot to limit the lifetime of resources
under RAII. How do you propose to address that (without needing
explicit del statements)? That's why the with statement exists, to
clearly define lifetimes smaller than "the enclosing function". Your
proposal doesn't offer any equivalent (other than an extra function).

Consider C++:

    void fn() {
        for (i = 0; i < 10000; ++i) {
            char name[100];
            sprintf(name, "file%d.txt, i);
            File f(name); // I don't think std::ofstream doesn't support RAII
            f << "Some text";
        }
    }

Or (real Python):

    def fn():
        for i in range(10000):
            with open(f"file{i}.txt", "w") as f:
                f.write("Some text")

How would you write this in your RAII style - without leaving 10,000
file descriptors open until the end of the function?

    def loop_body(i):
        f = open(f"file{i}.txt", "w")
        f.write("Some text")
    def fn():
        for i in range(10000):
            loop_body(i)

That's both less efficient (function calls have a cost) and less
maintainable than the with-statement version.

Paul



More information about the Python-list mailing list