From 2237a413a40a0d5725cd497103c14867fe806d3b Mon Sep 17 00:00:00 2001 From: Tobias Wrigstad Date: Wed, 14 May 2025 17:20:36 -0400 Subject: [PATCH 1/4] PEP: Deep Immutability for Python * initial * Made pep number an actual number to support building the HTML locally * Made agreed changes to PEP 9999 * Changes following comments from Matt P * Broken RST links fix * MJ comments * All fixed except figures * Fixed rST bugs Fixed broken code example * Adding example * Images * Images * Images * First finished draft * second take on pep * Made a complete pass * Tagged a bunch of things as TODO * Updated some parts according to discussions with Faster CPython team * Apply Matt P's suggestions from code review Co-authored-by: Matthew Parkinson * varia * Added note on modularisation * Minor tweaks * Remaining: rebasing + Brandt's comments * Resolved Brand't comments except the figure which is removed for now * Added two rejected alternatives for weak references * MJP's text on rebase on 3.14 Co-authored-by: Matthew Parkinson * Mostly done with Matt J's comments * Removed discrepancy in PEP and impl after Matt J additions * Apply suggestions from code review Co-authored-by: Fridtjof Stoldt * Update pep-9999.rst --------- Co-authored-by: Matthew Parkinson Co-authored-by: Fridtjof Stoldt --- pep-9999.rst | 936 ++++++++++++++++++++++++++++++++++++++++++ pep-9999/freeze1.svg | 3 + pep-9999/sharing1.png | Bin 0 -> 142215 bytes 3 files changed, 939 insertions(+) create mode 100644 pep-9999.rst create mode 100644 pep-9999/freeze1.svg create mode 100644 pep-9999/sharing1.png diff --git a/pep-9999.rst b/pep-9999.rst new file mode 100644 index 00000000000..35e1c959f1f --- /dev/null +++ b/pep-9999.rst @@ -0,0 +1,936 @@ +PEP: 9999 +Title: Deep Immutability in Python +Author: Matthew Johnson , Matthew Parkinson , Sylvan Clebsch , Fridtjof Peer Stoldt , Tobias Wrigstad +Sponsor: TBD +Discussions-To: TBD +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 27-Feb-2025 +Python-Version: 3.15 +Post-History: +Resolution: + + +Abstract +======== + +This PEP proposes adding a mechanism for deep immutability to +Python. The mechanism requires some changes to the core language, +but user-facing functions are delivered in a module called +``immutable``. This module provides the following functions and types: + +1. The function ``freeze(obj)`` -- turns ``obj`` deeply immutable +2. The function ``isfrozen(obj)`` -- returns ``True`` if ``obj`` is immutable +3. The function ``isfreezable(obj)`` -- returns ``True`` if all objects reachable from ``obj`` can be frozen +4. The type ``NotFreezable`` which is an empty type which cannot be frozen and can be used as a super class to classes whose instances should not be freezable +5. The type ``NotFreezableError`` which is raised on an attempt to mutate an immutable object +6. The function ``register_freezable(type)`` -- which is used to whitelist types implemented as C extensions, permitting their instances to be frozen + +Making an object *deeply* immutable recursively renders the object +*and all objects it references* immutable. (Just +making the first object immutable is called *shallow* +immutability.) + +Deep immutability provides strong guarantees against +unintended modifications, thereby improving correctness, security, and +parallel execution safety. + +Immutable objects are managed with reference counting plus cycle +detection just like normal mutable objects, and can be made +immortal. In this PEP, we rely on the GIL to ensure the +correctness of reference counts of immutable objects, but we have +several planned memory management extensions, including support +for atomic reference counting on immutable objects. These are +outlined at the end of this document. + +Immutability in action: + +.. code-block:: python + + from immutable import freeze, isfrozen + + class Foo: + pass + + f = Foo() + g = Foo() + h = Foo() + + f.f = g + g.f = h + h.f = g # cycles are OK! + del g # Remove local ref to g, so g's RC = 1 + del h # Remove local reg to h, so h's RC = 1 + + g.x = "African Swallow" # OK + freeze(f) # Makes, f, g and h immutable + g.x = "European Swallow" # Throws an exception "g is immutable" + isfrozen(h) # returns True + h = None # Cycle detector will eventually find and collect the cycle + + +Motivation +========== + + +Ensuring Data Integrity +----------------------- + +Python programs frequently manipulate large, interconnected data +structures such as dictionaries, lists, and user-defined objects. +Unintentional mutations can introduce subtle and +difficult-to-debug errors. By allowing developers to explicitly +freeze objects and their transitive dependencies, Python can +provide stronger correctness guarantees for data processing +pipelines, functional programming paradigms, and API boundaries +where immutability is beneficial. + + +Immutable Objects can be Freely Shared Without Risk of Data Races +----------------------------------------------------------------- + +Python’s Global Interpreter Lock (GIL) mitigates many data race +issues, but as Python evolves towards improved multi-threading and +parallel execution (e.g., subinterpreters and the free-threaded Python +efforts), data races on shared mutable objects become a more +pressing concern. A deep immutability mechanism ensures that +shared objects are not modified concurrently, enabling safer +multi-threaded and parallel computation. Safe sharing of immutable +objects across multiple threads require deep immutability. +Consider the following example: + +.. code-block:: python + + import threading + + data = [1, 2, 4, 8] + length = len(data) + pair = (data, length) + + threading.Thread(target=print, args=(pair,)).start() + + del data[2] + +The shallow immutability of the ``pair`` tuple prevents the +``data`` list from being swapped for another list, but the list +itself is not immutable. Thus, the ``print`` function in the newly +spawned thread will be racing with the deletion. In Python 3.12, +this is not a problem as the GIL prevents this race. To ensure +`container thread-safety +`_, PEP +703 proposes per-object locks instead. If ``pair`` was frozen, the +deletion would have caused an error. + +The following image illustrates that as soon as an object *a* +is reachable by two threads, then all other objects that +*a* can reach are also reachable by both threads. The dashed +red references to *c* and *d* are not possible because then +*c* and *d* would not be in areas where only a single thread +could reach them. + +To map the code example above to the figure -- ``pair`` is *a* and ``list`` is *b*. + +.. image:: pep-9999/sharing1.png + :width: 50% + +See also the discussion about extensions further down in this +document. + +Deep immutability can be implemented efficiently. An alternative approach +would be to detect data-races using a read-barrier based approach, however, +this cannot be implemented as efficiently. We discuss this in the alternatives +section. As highlighted above, immutability also has value in single-threaded +application, i.e. where there is no fear of data races. + + +Optimisations and Caching Benefits +---------------------------------- + +Immutable objects provide opportunities for optimisation, such as +structural sharing, memoization, and just-in-time (JIT) +compilation techniques (specialising for immutable data, e.g. +fixed shape, fewer barriers, inlining, etc.). Freezing objects can +allow Python to implement more efficient caching mechanisms and +enable compiler optimisations that rely on immutability +assumptions. This PEP will permit such opportunities to go +beyond today's immutable objects (like ``int``, ``string``) and +*shallow* immutable objects (``tuple``, ``frozenset``). + + + +Specification +============= + +Note: our current prototype implementation was authored on-top of +Python 3.12. To avoid blocking on rebasing on 3.14 to force +decisions about changes to implementation detail, we are +circulating this document to discuss the design ideas, +and some of the unaffected aspects of the implementation. + +An outline of the changes that we anticipate are required for +Python 3.14 is can be found at the `end of the document `_. + + +Changes to Python Objects +------------------------- + +Every Python object will have a flag that keeps track of its +immutability status. Details about the default value of +this flag is discussed further down in this document. + +The flag can be added without extending the size of the +Python object header. + + +Implementation of Immutability +------------------------------ + +Immutability is enforced through run-time checking. The macro +``Py_CHECKWRITE(op)`` is inserted on all paths that are guaranteed +to end up in a write to ``op``. The macro inspects the immutability +flag in the header of ``op`` and signals an error if the immutability +flag is set. + +A typical use of this check looks like this: + +.. code-block:: c + + if (!Py_CHECKWRITE(op)) { // perform the check + PyErr_WriteToImmutable(op); // raise the error if the check fails + return NULL; // abort the write + } + ... // code that performs the write + + +Writes are common in the CPython code base and the writes lack a +common "code path" that they pass. To this end, the PEP requires a +``Py_CHECKWRITE`` call to be inserted and there are several places +in the CPython code base that are changed as a consequence of this +PEP. So far we have identified around 70 places in core Python which +needed a ``Py_CHECKWRITE`` check. Modules in the standard library +have required somewhere between 5 and 15 checks per module. + + +Backward Compatibility +====================== + +This proposal intends to be fully backward compatible, as no existing Python +code will be affected unless it explicitly calls ``freeze(obj)``. +Frozen objects will raise errors only when mutation is attempted. + + +Opt-In vs. Opt-Out +------------------ + +All pure Python objects can be frozen, provided all their members +and their base classes can be frozen. However, for types which +are partially or completely implemented in C, support for +immutability requires some work on both exposing objects to +freezing, and to enforce immutability in mutating C-functions. + +From a backwards compatibility perspective, an opt-in model keeps +things simple: all existing code keeps working, and only code that +wishes to support immutability needs updating. The downside of the +opt-in model is that a large part of all Python libraries cannot +be (even nominally) frozen. + +This PEP proposes to make support for immutability in C extensions +and Python wrappers of classes which would otherwise not be freezable +opt-in through a whitelisting mechanism implemented through the +function ``register_freezable(type)`` in the ``immutable`` module. + +Note that it is possible to mix modules and types that support +immutability with those that do not, as long as this does not +breaks strictness. + + +Strictness +---------- + +A strict interpretation of deep immutability does not permit an +immutable object to reference a mutable object. This model is both +easy to explain and understand, and an object's immutability can +be "trusted" --- it is not possible for an immutable object to +change through some nested mutable state [#RC]_. At the same time +it limits the utility of freezing as many Python objects contain +types outside of the standard library defined in C, which must +opt-in immutability before they can be frozen. + +This PEP proposes immutability to be strict. + + +Dealing with Failure During Freezing +------------------------------------ + +Regardless whether support for freezing is opt-in or opt-out some +types will not be freezable. (Example such types include IO types +like file handles, and caches -- as opposed to the cached +objects.) This raises the question how to handle failure to freeze +an object graph. Consider the object graph ``o1 --> o2 --> o3`` +where ``o1`` and ``o3`` can be frozen, but ``o2`` cannot. What are +the possible behaviours of ``freeze(o1)``? + +1. Freeze fails partially. All subgraphs which could be frozen + entirely remain frozen. Remaining objects remain mutable. In + our example, ``o3`` remains frozen but ``o1`` and ``o2`` remain + mutable. This preserves strict immutability. The exception + thrown by the failing ``freeze(o1)`` call will contain ``o2`` + (the place that caused freezing to fail) and ``o1`` (the object + in the graph that holds on to the failing object) to facilitate + debugging. +2. **Rejected alternative**: Freeze fails completely. In the strict + interpretation of deep immutability, freezing ``o1`` is not + possible because ``o1`` contains a reference to an un-freezable + object ``o2``. In this scenario, the object graph ``o1 --> o2 + --> o3`` remains mutable and ``freeze(o1)`` raises an exception + when the object graph traversal encounters ``o2``. +3. **Rejected alternative**: Freeze succeeds by altering the + graph. In this example removing ``o2`` from the graph or + swapping out ``o2`` for a placeholder object to be able to + freeze the graph. This alternative becomes complicated both to + reason about from a user's perspective, and to implement when + ``o2`` is referenced multiple times. +4. **Rejected alternative**: Permit the user to choose between + alternatives 1) and 3) at use-site. In this case, the + ``freeze`` function takes an optional 2nd argument ``strict`` + which must either be ``True`` or ``False``. In the first case, + ``freeze`` behaves as in alternative 1), in the second case, + it behaves as in alternative 2). We could further track whether + an object is strictly immutable or not in order to prevent + non-strictly immutable objects to participate in operations + which require strictness. This adds additional complexity to + the implementation, and also for the user. + +This PEP proposes following alternative 1, where freezing either +succeeds or fails partially. + + +New Obligations on C Extensions +------------------------------- + +Due to the opt-in decision, there are no *obligations* for C +extensions that do not want to add support for immutability. + +Because our implementation builds on information available to the CPython +cycle detector, types defined through C code will support immutability +"out of the box" as long as they use Python standard types to store +data and uses the built-in functions of these types to modify the data. + +To make its instances freezable, a type that uses C extensions +that adds new functionality implemented in C must register +themselves using ``register_freezable(type)``. Example: + +.. code-block:: Python + + PyObject *register_freezable = _PyImport_GetModuleAttrString("immutable", "register_freezable"); + if(register_freezable != NULL) + { + PyObject* result = PyObject_CallOneArg(register_freezable, (PyObject *)st->Element_Type); + if(result == NULL){ + goto error; + } + + Py_DECREF(register_freezable); + } + +If you construct a C type using freezable metaclasses it will itself be freezable, +without need for explicit registration. + +To properly support immutability, C extensions that directly write +to data which can be made immutable should add the +``Py_CHECKWRITE`` macro shown above on all paths in the code that +lead to writes to that data. Notably, if C extensions manage their +data through Python objects, no changes are needed. + +**Rejected alternative**: Python objects may define a +``__freeze__`` method which will be called **after** an object has +been made immutable. This hook can be used to freeze or otherwise +manage any other state on the side that is introduced through a +C-extension. + +C extensions that define data that is outside of the heap traced +by the CPython cycle detector should either manually implement +freezing by using ``Py_CHECKWRITE`` or ensure that all accesses to +this data is *thread-safe*. There are cases where too strict +adherence to immutability is undesirable (as exemplified by our +mutable reference counts), but ideally, it should not be able to +directly observe these effects. (For example, taking the reference +count of an immutable object is not supported to prevent code from +branching on a value that can change non-deterministically by +actions taken in parallel threads.) + + +Examples of Uses of CHECKWRITE +------------------------------ + +Inspiration and examples can be found by looking at existing +uses of ``Py_CHECKWRITE`` in the CPython codebase. Two good +starting places are ``object.c`` `[1]`_ and ``dictobject.c`` `[2]`_. + +.. _[1]: https://github.com/mjp41/cpython/pull/51/files#diff-ba56d44ce0dd731d979970b966fde9d8dd15d12a82f727a052a8ad48d4a49363 +.. _[2]: https://github.com/mjp41/cpython/pull/51/files#diff-b08a47ddc5bc20b2e99ac2e5aa199ca24a56b994e7bc64e918513356088c20ae + +Deep Freezing Semantics +======================= + +Following the outcomes of the design decisions discussed just +above, the ``freeze(obj)`` function works as follows: + +1. It recursively marks ``obj`` and all objects reachable from ``obj`` + immutable. +2. If ``obj`` is already immutable (e.g., an integer, string, or a + previously frozen object), the recursion terminates. If ``obj`` cannot + be frozen, the entire freeze operation is aborted without making any + object immutable. +3. The freeze operation follows object references (relying on ``tp_traverse`` + in the type structs of the objects involved), including: + + * Object attributes (``__dict__`` for user-defined objects, + ``tp_dict`` for built-in types). + * Container elements (e.g., lists, tuples, dictionaries, + sets). + * The ``__class__`` attribute of an object (which makes freezing + instances of user-defined classes also freeze their class + and its attributes). + * The ``__bases__`` chain in classes (freezing a class freezes its + base classes). + +5. Attempting to mutate a frozen object raises a type error + with a self-explanatory message. + + +Illustration of the Deep Freezing Semantics +------------------------------------------- + +Consider the following code: + +.. code-block:: python + + class Foo: + pass + + x = Foo() + x.f = 42 + + +The ``Foo`` instance pointed to by ``x`` consists of several +objects: its fields are stored in a dictionary object, and the +assignment ``x.f = 42`` adds two objects to the dictionary in the +form of a string key ``"f"`` and its associated value ``42``. +These objects each have pointers to the ``string`` and ``int`` +type objects respectively. Similarly, the ``foo`` instance has a +pointer to the ``Foo`` type object. Finally, all type objects have +pointers to the same meta class object (``type``). + +Calling ``freeze(x)`` will freeze **all** of these objects. + + +Default (Im)Mutabiliy +--------------------- + +Except for the type object for ``NotFreezable``, no objects are +immutable by default. + +**Rejected alternative**: Interned strings, numbers in the small +integer cache, and tuples of immutable objects could be made +immutable in this PEP. This is either consistent with current +Python semantics or backwards-compatible. We have rejected this +for now as we have not seen a strong need to do so. (A reasonable +such design would make *all* numbers immutable, not just those in +the small integer cache. This should be properly investigated.) + + +Consequences of Deep Freezing +============================= + +* The most obvious consequence of deep freezing is that it can lead + to surprising results when programmers fail to reason correctly + about the object structures in memory and how the objects reference + each other. For example, consider ``freeze(x)`` followed by + ``y.f = 42``. If the object in ``x`` can reach the same object that + ``y`` points to, then, the assignment will fail. **Mitigation:** To + facilitate debugging, exceptions due to attempting to mutate immutable + objects will include information about on what line an object was made + immutable. +* Class Freezing: Freezing an instance of a user-defined class + will also freeze its class. Otherwise, sharing an immutable object + across threads would lead to sharing its *mutable* type object. Thus, + freezing an object also freezes the type type object of its super + classes. This means that any metaprogramming or changes to a class + must happen before a class is frozen. **Mitigation:** A frozen class + can be extended and its behaviour overridden through normal object-oriented + means. If neccessary, it is possible to add an option to make a mutable + copy of immutable objects and classes, which could then be changed. + Mutable instances of an immutable class can have their classes changed + to the mutable copy by reassigning ``__class__``. +* Metaclass Freezing: Since class objects have metaclasses, + freezing a class may propagate upwards through the metaclass + hierarchy. This means that the ``type`` object will be made immutable + at the first call of ``freeze``. **Mitigation:** We have not explored + mitigation for this, and we are also not aware of major problems + stemming from this design. +* Global State Impact: Although we have not seen this during our + later stages of testing, it is possible that freezing an object that references + global state (e.g., ``sys.modules``, built-ins) could + inadvertently freeze critical parts of the interpreter. + **Mitigation:** Avoiding accidental freezing is possible by + inheriting from (or storing a pointer to) the ``NotFreezable`` + class. Also, when the Python interpreter is exiting, we make all + immutable objects mutable to facilitate a clean exit of the + interpreter. Also note that it is not possible to effectively + disable module imports by freezing. + +As the above list shows, a side-effect of freezing an object is +that its type becomes frozen too. Consider the following program, +which is not legal in this PEP because it modifies the type of an +immutable object: + +.. code-block:: python + + from immutable import freeze + + class Counter: + def __init__(self, initial_value): + self.value = initial_value + def inc(self): + self.value += 1 + def dec(self): + self.value -= 1 + def get(self): + return self.value + + c = Counter(0) + c.get() # returns 0 + freeze(c) # (*) -- this locks the value of the counter to 0 + ... + Counter.get = lambda self: 42 # throws exception because Counter is frozen + c.get() # would have returned 42 unless the line above had been "stopped" + +With this PEP, the code above throws an exception on +Line (*) because the type object for the ``Counter`` type +is immutable. Our freeze algorithm takes care of this as +it follows the class reference from ``c``. If we did not +freeze the ``Counter`` type object, the above code would +work and the counter will effectively be mutable because +of the change to its class. + +The dangers of not freezing the type is apparent when considering +avoiding data races in a concurrent program. If a frozen counter +is shared between two threads, the threads are still able to +race on the ``Counter`` class type object. + +As types are frozen, this problem is avoided. Note that +freezing a class needs to freeze its superclasses as well. + + +Subclassing Immutable Classes +----------------------------- + +CPython classes hold references to their subclasses. If +immutability it taken literally, it would not be permitted to +create a subclass of an immutable type. Because this reference +does not get exposed to the programmer in any dangerous way, we +permit frozen classes to be subclassed (by mutable classes). C.f. +`Sharing Immutable Data Across Subinterpreters`_. + + +Freezing Function Objects +------------------------- + +Function objects can be thought of as regular objects whose fields +are its local variables -- some of which may be captured from +enclosing scopes. Thus, freezing function objects and lambdas is +surprisingly involved. + +Consider the following scenario: + +.. code-block:: python + + from immutable import freeze + + def example1(): + x = 0 + + def foo(): + return x + + freeze(foo) + ... # some code, e.g. pass foo to another thread + x = 1 + foo() + + example1() + +In the code above, the ``foo`` function object captures the ``x`` +variable from its enclosing scope. While ``x`` happens to point to +an immutable object, the variable itself (the frame of the function object) +is mutable. Unless something is done to prevent it (see below!), passing +``foo`` to another thread will make the assignment ``x = 1`` a potential +data race. + +We consider freezing of a function to freeze that function's +meaning at that point in time. In the code above, that means that +``foo`` gets its own copy of ``x`` which will have value of the enclosing +``x`` at the time of freezing, in this case 0. + +Thus, the assignment ``x = 1`` is still permitted as it will not affect +``foo``, and it may therefore not contribute to a data race. Furthermore, +the result of calling ``foo()`` will be 0 -- not 1! + +This is implemented by having ``x`` in ``foo`` point to a fresh +cell and then freezing the cell (and similar for global capture). +Note that this also prevents ``x`` from being reassigned. + +We believe that this design is a sweet-spot that is intuitive and +permissive. Note that we will treat freezing functions that +capture enclosing state in the same way regardless of whether the +enclosing state is another function or the top-level (i.e., the +enclosing scope is ``globals()``). + +(A **rejected alternative** is to freeze ``x`` in the +enclosing scope. This is problematic when a captured variable is +in ``globals()`` and also rejects more programs.) + +Now consider freezing the following function: + +.. code-block:: python + + from immutable import freeze + + def example2(): + x = 0 + def foo(a = False): + if a: + a = a + 1 # Note: updating local variables work, even in a frozen function + return a + else: + x = x + 1 + return x + + freeze(foo) + foo(41) # OK, returns 42 + foo() # Throws NotWriteableError + + example2() + +This example illustrates two things. The first call to ``foo(41)`` +shows that local variables on the frame of a frozen function are +mutable. The second call shows that captured variables are not. +Note that the default value of ``a`` will be frozen when ``foo`` +is frozen. Thus, the problem of side-effects on default values +on parameters is avoided. + +Frozen function objects that access globals, e.g. through an +explicit call to ``globals()``, will throw an exception when +called. + + +Implementation Details +====================== + +1. Add the ``immutable`` module, the ``NotWriteableError`` type, and + the ``NotFreezable`` type. +2. Add the ``freeze(obj)`` function to the ``immutable`` module and + ensure that it traverses object references safely, including + cycle detection, and marks objects appropriately, and backs + out on failure, possibly partially freezing the object graph. +3. Add the ``isfreezable(obj)`` function which checks that all + objects reachable from ``obj`` can be frozen. +4. Add the ``register_freezable(type)`` function that is used to + whitelist types implemented as C extensions, permitting their + instances to be frozen. +6. Add the ``isfrozen(obj)`` function to the ``immutable`` module + that checks whether or not an object is frozen. The status + is accessible through ``_Py_ISIMMUTABLE`` in the C API and in + Python code through the ``isfrozen(obj)`` function. +7. Modify object mutation operations (``PyObject_SetAttr``, + ``PyDict_SetItem``, ``PyList_SetItem``, etc.) to check the + flag and raise an error when appropriate. +8. Modify mutation operations in modules in the standard library. + + +Changes to the C ABI +-------------------- + +* ``Py_CHECKWRITE`` +* ``_Py_IsImmutable`` +* ``PyErr_WriteToImmutable`` + +Changes to the internal API +--------------------------- + +* ``_PyType_HasExtensionSlots(PyTypeObject*)`` -- determines whether a TypeObject adds novel functionality in C +* ``_PyNotFreezable_Type`` +* ``_PyImmutability_Freeze`` +* ``_RegisterFreezable`` +* ``_PyImmutability_IsFreezable`` + + + + +Performance Implications +======================== + +The cost of checking for immutability violations is +an extra dereference of checking the flag on writes. +There are implementation-specific issues, such as +various changes based on how and where the bit is stolen. + + +More Rejected Alternatives +========================== + +1. Shallow Freezing: Only mark the top-level object as immutable. + This would be less effective for ensuring true immutability + across references. In particular, this would not make it safe + to share the results of ``freeze(obj)`` across threads without risking + data-race errors. Shallow immutability is not strong enough to support + sharing immutable objects across subinterpreters (see extensions). +2. Copy-on-Write Immutability: Instead of raising errors on + mutation, create a modified copy. However, this changes object + identity semantics and is less predictable. Support for copy-on-write + may be added later, if a suitable design can be found. +3. Immutable Subclasses: Introduce ``ImmutableDict``, ``ImmutableList``, + etc., instead of freezing existing objects. However, this does + not generalize well to arbitrary objects and adds considerable + complexity to all code bases. +4. Deep freezing immutable copies as proposed in `PEP 351: The + freeze protocol `_. That PEP + is the spiritual ancestor to this PEP which tackles the + problems of the ancestor PEP and more (e.g. meaning of + immutability when types are mutable, immortality, etc). +5. Deep freezing replaces data races with exceptions on attempts to + mutate immutable objects. Another alternative would be to keep + objects mutable and build a data-race detector that catches read--write + and write--write races. This alternative was rejected for two main + reasons: + + 1. It is expensive to implement: it needs a read-barrier to + detect what objects are being read by threads to capture + read--write races. + 2. While more permissive, the model suffers from non-determinism. + Data races can be hidden in corner cases that require complex + logic and/or temporal interactions which can be hard to + test and reproduce. + + +A Note on Modularisation +======================== + +While the ``freeze(obj)`` function is available to Python programmers +in the ``immutable`` module, the actual freezing code has to live +inside core Python. This is for three reasons: + +1. The core object type needs to be able to freeze just-in-time + dictionaries created by its accessors when the object itself is + frozen. +2. The managed buffer type needs to be frozen when the object it + is created from is frozen. +3. Teardown of strongly connected components of immutable objects + (see `Simplified Garbage Collection for Immutable Object + Graphs`_) must be hooked into ``Py_DECREF``. + +As such, we implement a function which is not in the limited API +(and thus not part of the stable C ABI) called ``_PyImmutability_Freeze`` +which performs the freezing logic. This is used internally as a C +Python implementation detail, and then exposed to Python through +the ``freeze(obj)`` function in the ``immutable`` module. + + +Weak References +=============== + +Weak references are turned into strong references during freezing. +Thus, an immutable object cannot be effectively mutated by a +weakly referenced nested object being garbage collected. If a weak +reference loses its object during freezing, we treat this as a +failure to freeze since the program is effectively racing with the +garbage collector. + +A **rejected alternative** is to nullify the weak reference during +freezing. This avoid the promotion to a strong reference while +ensures that the immutable object stays the same throughout its +lifetime, but probably has the unwanted semantics of pruning the +object graph while freezing it. (Imagine a hash table with weak +references for its keys -- if freezing it removes all its keys, +the hash table is essentially useless.) + +Another **rejected alternative** is to simply leave weak references +as is. This was rejected as it makes immutable objects effectively +mutable and access to shared immutable objects can race on accesses +to weak references. + + +Future Extensions +================= + +This PEP is the first in a series of PEPs with the goal of delivering +a Data-Race Free Python that is theoretically compatible with, but +notably not contigent on, `PEP 703`_. + +This work will take place in the following discrete steps: + +1. Support for identifying and freeing cyclic immutable garbage + using reference counting. +2. Support for sharing immutable data across subinterpreters using + atomic reference counting of immutable objects to permit + concurrent increments and decrements on shared object RC's. +3. Support for sharing mutable data across subinterpreters, with + dynamic ownership protecting against data races. +4. Package all of the above into "Data-Race Free Python" + +Note that each step above adds something which is directly useful +to Python even before a subsequent step is taken. + + +Simplified Garbage Collection for Immutable Object Graphs +--------------------------------------------------------- + +In `previous work `_, +we have identified that objects that make up cyclic immutable +garbage will always have the same lifetime. This means that a +single reference count could be used to track the lifetimes of +all the objects in such a strongly connected component (SCC). + +We plan to extend the freeze logic with a SCC analysis that +creates a designated (atomic) reference count for the entire +SCC, such that reference count manipulations on any object in +the SCC will be "forwarded" to that shared reference count. +This can be done without bloating objects by repurposing the +existing reference counter data to be used as a pointer to +the shared counter. + +This technique permits handling cyclic garbage using plain +reference counting, and because of the single reference count +for an entire SCC, we will detect when all the objects in the +SCC expire at once. + +This approach requires a second bit. Our `reference implementation`_ +already steals this bit in preparation for this extension. + + +Support for Atomic Reference Counting +------------------------------------- + +As a necessary requirement for the extension `Sharing Immutable Data Across Subinterpreters`_, +we will add support for atomic reference counting for immutable objects. This +will complement work in `Simplified Garbage Collection for Immutable Object Graphs`_, +which aims to make memory management of immutable data more efficient. + +When immutable data is shared across threads we must ensure that +concurrent reference count manipulations are correct, which in turns +requires atomic increments and decrements. Note that since we are only +planning to share immutable objects across different GIL's, it is +*not* possible for two threads to read--write or write--write race +on a single field. Thus we only need to protect the reference counter +manipulations, avoiding most of the complexity of `PEP 703`_ + + +Sharing Immutable Data Across Subinterpreters +--------------------------------------------- + +We plan to extend the functionality of `multiple subinterpreters `_ +to *share* immutable data without copying. This is safe and +efficient as it avoids the copying or serialisation when +objects are transmitted across subinterpreters. + +This change will require reference counts to be atomic (as +discussed above) and the subclass list of a type object to +be made thread-safe. Additionally, we will need to change +the API for getting a class' subclasses in order to avoid +data races. + +This change requires modules loaded in one subinterpreter to be +accessible from another. + + +Data-Race Free Python +--------------------- + +While useful on their own, all the changes above are building +blocks of Data-Race Free Python. Data-Race Free Python will +borrow concepts from ownership (namely region-based ownership, +see e.g. `Cyclone `_) to make Python programs data-race free +by construction. Which will permit multiple subinterpreters to +share *mutable* state, although only one subinterpreter at a time +will be able to access (read or write) to that state. +This work is also compatible with free-theaded Python (PEP 703). + +A description of the ownership model can be found in a paper accepted +for PLDI 2025 (an academic conference on design and implementation of +programming languages): `Dynamic Region Ownership for Concurrency +Safety `_. + +It is important to point out that Data-Race Free Python is different +from `PEP 703`_, but aims to be fully compatible with that PEP, and +we believe that both PEPs can benefit from each other. In essence +`PEP 703`_'s focus is on making the CPython run-time resilient against +data races in Python programs: a poorly synchronized Python program +should not be able to corrupt reference counts, or other parts of +the Python interpreter. The complementary goal pursued by this PEP +is to make it impossible for Python programs to have data races. +Support for deeply immutable data is the first important step +towards this goal. + + +Reference Implementation +======================== + +`Available here `_. + +There are some discrepancies between this PEP and the reference +implementation, including: + +- The ``isfreezable(obj)`` function is not yet implemented. +- The ``NotFreezable`` type is currently freezable (but inheriting + from it stops instances of the inheriting class from being frozen). + + +Rebasing on Python 3.14 +======================= + +We have found two areas that need to be addressed to integrate this work with "free-threaded Python": data-representation and data-races during freeze. + +Data-representation for immutability +------------------------------------ + +With free-threaded Python the representation of the reference count has been changed. We could either borrow a bit to represent if an object is frozen, or alternatively, we could use the new `ob_tid` field to have a special value for immutable state. Using `ob_tid` would allow for standard mutable thread local objects to remain the fast path, and is our preferred alternative. + +The extensions use use SCC calculations to detect cycles in immutable graphs, would require additional state. Repurposing `ob_tid` and `ob_ref_shared` would allow sufficient space for the necessary calculation. + +Data-races during freeze +------------------------ + +We consider the following races + +- Freezing some objects concurrently with another thread checking if a graph is immutable. +- Freezing some objects concurrently with another thread mutating those objects. +- Freezing some objects concurrently with another thread freezing those objects. + +To address the first race, we need to consider strictness of deep immutability. We need to ensure that querying an object graph for immutability only says yes if it is deeply immutable. This requires a two step immutable state: immutable but not strict, and then immutable and strict. On a DFS traversal of the object graph items are marked as immutable but not strict on the pre-order step, and then immutable and strict on the post-order step. To query if a graph is immutable, we will require the "immutable and strict" state. + +Handling mutation during freeze can use the mutex added by free-threading. There are some cases where mutation does not require the acquisition of a mutex, which would no longer allowed with this feature. Freezing would be required to lock the object, marks it as immutable, release the lock, and then read all its fields. + +The final case is the most complex detecting parallel freezing of an object graph. We will consider this an error. This error can be detected as follows. If we encounter an object that is "immutable but not strict", then this should be on the path to the current object from the starting point of the freeze. If this is not the case, then we must be observing another thread freezing an object graph. The algorithm should back out the pending aspects of freeze, and raise an exception to the user. This can naturally be integrated with the SCC algorithm. + + +References +========== + +* `PEP 703: Making the Global Interpreter Lock Optional in CPython `_ +* `PEP 351: The freeze protocol `_ +* `PEP 734: Multiple Interpreters in the Stdlib `_ +* `PEP 683: Immortal Objects, Using a Fixed Refcount `_ + +.. _PEP 703: https://peps.python.org/pep-0703 + + +.. rubric:: Footnotes + +.. [#RC] Note that the same logic does not apply to e.g. an + object's reference count. The reference count is + metadata about an object that is stored in the object + for purely pragmatic reasons, but this data really + belongs to the memory management logic of the + interpreter, not the object itself. diff --git a/pep-9999/freeze1.svg b/pep-9999/freeze1.svg new file mode 100644 index 00000000000..0574959f1d6 --- /dev/null +++ b/pep-9999/freeze1.svg @@ -0,0 +1,3 @@ + + +

__dict__

value

__class__

__class__

key

__class__

__class__

__class__

__class__

Foo instance

Foo instance's field dict

42

Int class obj

Meta class obj

'f'

String class obj

Foo class obj

diff --git a/pep-9999/sharing1.png b/pep-9999/sharing1.png new file mode 100644 index 0000000000000000000000000000000000000000..d8484a3bf24fe856fc4b53da613eb73e7b96ff35 GIT binary patch literal 142215 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 z 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
    ma*!mlZ1{2G{)|Hd#qePvD3jmCO79 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%0A!L5ry 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 z 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 WZHRo3%(w^sk$fpDS}3CX@&5oVA-ul; literal 0 HcmV?d00001 From 6d60fe5522f74dcc4698c9f3b170afca8573b161 Mon Sep 17 00:00:00 2001 From: Tobias Wrigstad Date: Wed, 14 May 2025 17:32:47 -0400 Subject: [PATCH 2/4] Added sponsor --- pep-9999.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-9999.rst b/pep-9999.rst index 35e1c959f1f..7b63dd77fc7 100644 --- a/pep-9999.rst +++ b/pep-9999.rst @@ -1,7 +1,7 @@ PEP: 9999 Title: Deep Immutability in Python Author: Matthew Johnson , Matthew Parkinson , Sylvan Clebsch , Fridtjof Peer Stoldt , Tobias Wrigstad -Sponsor: TBD +Sponsor: Michael Droettboom Discussions-To: TBD Status: Draft Type: Standards Track From d77cbe2687e57c6b0debb1b98b4c27f507531b7e Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Fri, 16 May 2025 04:13:37 -0400 Subject: [PATCH 3/4] Update pep-9999.rst --- pep-9999.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/pep-9999.rst b/pep-9999.rst index 7b63dd77fc7..5baf1ed563c 100644 --- a/pep-9999.rst +++ b/pep-9999.rst @@ -601,6 +601,7 @@ Now consider freezing the following function: def example2(): x = 0 def foo(a = False): + nonlocal x if a: a = a + 1 # Note: updating local variables work, even in a frozen function return a From 7a2d24f2851f499e44e4b49e3b68a7725913b81b Mon Sep 17 00:00:00 2001 From: Tobias Wrigstad Date: Mon, 11 Aug 2025 12:06:01 +0200 Subject: [PATCH 4/4] Rewrite of PEP795 --- peps/pep-0795.rst | 2450 ++++++++++++++++++++++++++++++++++ peps/pep-0795/diagram_1.mmd | 24 + peps/pep-0795/diagram_1.svg | 1 + peps/pep-0795/diagram_10.mmd | 29 + peps/pep-0795/diagram_10.svg | 1 + peps/pep-0795/diagram_11.mmd | 33 + peps/pep-0795/diagram_11.svg | 1 + peps/pep-0795/diagram_12.mmd | 50 + peps/pep-0795/diagram_12.svg | 1 + peps/pep-0795/diagram_2.mmd | 18 + peps/pep-0795/diagram_2.svg | 1 + peps/pep-0795/diagram_3.mmd | 8 + peps/pep-0795/diagram_3.svg | 1 + peps/pep-0795/diagram_4.mmd | 14 + peps/pep-0795/diagram_4.svg | 1 + peps/pep-0795/diagram_5.mmd | 14 + peps/pep-0795/diagram_5.svg | 1 + peps/pep-0795/diagram_6.mmd | 9 + peps/pep-0795/diagram_6.svg | 1 + peps/pep-0795/diagram_7.mmd | 10 + peps/pep-0795/diagram_7.svg | 1 + peps/pep-0795/diagram_8.mmd | 28 + peps/pep-0795/diagram_8.svg | 1 + peps/pep-0795/diagram_9.mmd | 41 + peps/pep-0795/diagram_9.svg | 1 + 25 files changed, 2740 insertions(+) create mode 100644 peps/pep-0795.rst create mode 100644 peps/pep-0795/diagram_1.mmd create mode 100644 peps/pep-0795/diagram_1.svg create mode 100644 peps/pep-0795/diagram_10.mmd create mode 100644 peps/pep-0795/diagram_10.svg create mode 100644 peps/pep-0795/diagram_11.mmd create mode 100644 peps/pep-0795/diagram_11.svg create mode 100644 peps/pep-0795/diagram_12.mmd create mode 100644 peps/pep-0795/diagram_12.svg create mode 100644 peps/pep-0795/diagram_2.mmd create mode 100644 peps/pep-0795/diagram_2.svg create mode 100644 peps/pep-0795/diagram_3.mmd create mode 100644 peps/pep-0795/diagram_3.svg create mode 100644 peps/pep-0795/diagram_4.mmd create mode 100644 peps/pep-0795/diagram_4.svg create mode 100644 peps/pep-0795/diagram_5.mmd create mode 100644 peps/pep-0795/diagram_5.svg create mode 100644 peps/pep-0795/diagram_6.mmd create mode 100644 peps/pep-0795/diagram_6.svg create mode 100644 peps/pep-0795/diagram_7.mmd create mode 100644 peps/pep-0795/diagram_7.svg create mode 100644 peps/pep-0795/diagram_8.mmd create mode 100644 peps/pep-0795/diagram_8.svg create mode 100644 peps/pep-0795/diagram_9.mmd create mode 100644 peps/pep-0795/diagram_9.svg diff --git a/peps/pep-0795.rst b/peps/pep-0795.rst new file mode 100644 index 00000000000..2bbba6b59a9 --- /dev/null +++ b/peps/pep-0795.rst @@ -0,0 +1,2450 @@ +PEP: 795 +Title: Deep Immutability for Efficient Sharing and Concurrency Safety +Author: Matthew Johnson , Matthew Parkinson , Sylvan Clebsch , Fridtjof Peer Stoldt , Tobias Wrigstad +Sponsor: Michael Droettboom +Discussions-To: TBD +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 27-Feb-2025 +Python-Version: 3.15 +Post-History: +Resolution: + + +Deep Immutability for Efficient Sharing and Concurrency Safety +============================================================== + +This PEP proposes support for deeply immutable objects in Python. This +PEP distinguishes between objects which are **mutable**, **deeply +immutable**, or **freezable**. Mutable objects can be updated and +reference both mutable and deeply immutable objects. Deeply immutable +objects cannot be updated, and may only point to other deeply immutable +objects. A freezable objects is like a mutable objects except that it +can be turned into an immutable object. We refer to the act +of making a freezable object immutable as “freezing it”. +There is no way to make an immutable object mutable again. +However, one can make a mutable copy of an immutable object. + +From now on, we will use immutable to mean deeply immutable, and use +**shallow immutability** to mean the protection offered by tuples and +frozen sets in Python 3.14. For example, ``(42, (4711, None))`` is +deeply immutable, but ``(42, [4711, None])`` is only shallowly +immutable, because the list constructor creates a mutable object. + +Motivation +---------- + +The motivation for immutability is four-fold: + +1. Immutability is a very useful concept in programming that simplifies + reasoning about state. In particular immutable objects are safe to + share between concurrent threads without any synchronisation in the + program. +2. With the semantics of immutability that this PEP proposes, immutable + objects can be shared directly by reference across sub-interpreters. + This is a big performance boost for sub-interpreters as Python + currently requires objects to be transferred across sub-interpreters + by pickling. This also simplifies programming with sub-interpreters. + To make this safe, some changes are necessary with respect to how a + Python interpreter manages the memory of immutable objects. (Note + that this is not possible without *deep* immutability.) +3. Since immutable objects are safe from data races, it is possible to + avoid some of the overhead surrounding field access that is needed + for correct reference counting in free-threaded Python. +4. Memory for immutable objects can be safely managed without leaks + without cycle detection, even when there are cycles in the immutable + objects. This takes pressure off normal cycle detection in both + sub-interpreters and free-threading, and is key to sharing objects + between sub-interpreters without needing substantial changes to cycle + detection. + +In this PEP, we strive to create a semantics for immutable objects that +is consistent across both sub-interpreters and free-threaded Python. +This is a difficult problem as sub-interpreters rely on isolation plus a +per-interpreter GIL for correctness, whereas free-threading has no GIL. + +In a future PEP, we will propose a scheme for sharing *mutable* objects +by reference across sub-interpreters. There is a short note about this +at the end of this document. + +About the structure of this PEP +------------------------------- + +This PEP describes three stages of immutability support in Python. Each +stage permit more objects to be immutable. Permitting more objects to be +immutable requires more changes to the Python interpreter, and +additionally come with design considerations at the language level. +While we foresee no technical problems with getting to the third stage +already in Python 3.15, discussions at DPO prompted the split of this +PEP into stages to clarify the “return on investement” for each step and +also permitting this change to be rolled out across multiple releases to +give the Python community more time to get accustomed to immutability. +At a high-level, the three stages are: + +1. Objects and types which are de-facto immutable in Python 3.14 are + immutable according to this PEP +2. Extend immutability to user-defined types and their instances – but + no “monkey patching” of types (e.g. adding and removing methods, or + class variables) +3. Permit monkey patching of types before they become immutable + +This PEP is a complete rewrite of the original PEP after `discussions on +DPO `__ +and elsewhere. Based on feedback from DPO this rewrite: + +- Focuses more on programming model, not just implementation details +- Aims to be clearer about what the costs are for different parts of + the design, both in terms of complexity for programmers and + implementers of this PEP +- Aims to make the semantics of freezing clearer, and provide more + examples of how freezing propagates +- Adds a new design that limits freeze propagation +- Adds escape hatches +- Motivates the design by linking it clearer to sharing objects across + sub-interpreters +- Made minor naming changes to avoid confusion with frozen modules +- Aims to be clearer about the semantics of immutable functions (and why + they are unavoidable) +- Discusses the role of types and future plans for types +- Includes direct sharing of immutable objects across sub-interpreters, + rather than making a separate PEP for this +- Removes a lot of the rejected alternatives from the original PEP; + this is motivated by this PEP already being very long, and because + the inclusion of direct sharing across sub-interpreters motivate many + of the design decisions + +We are very greatful to the many comments and threads on DPO that have +contributed to this PEP. + +Design considerations due to sub-interpreters +--------------------------------------------- + +Because this PEP makes immutable objects directly sharable across +sub-interpreters, the design is influenced by constraints in the +sub-interpreter model. This section explains those at a high-level. + +In this PEP, when we talk about sub-interpreters, we always mean +sub-interpreters configured to use their own GIL +(``PyInterpreterConfig_OWN_GIL``) so as to permit efficient use of +multiple cores in a Python program. Quoting from Python/C API Reference +manual, the section on Initialization, Finalization, and Threads, in +`Sub-interpreter +support `__: + + Sub-interpreters are most effective when isolated from each other, + with certain functionality restricted + +The restriced functionality notably includes that sub-interpreters may +not share objects by reference – each sub-interpreter should be +isolated. This isolation permits a sub-interpreter to use its own GIL to +ensure that reference count manipulation and cycle detection cannot be +corrupted due to concurrency in the Python program. Quoting again from +the `same source as +above `__: + + If you preserve isolation then you will have access to proper + multi-core computing without the complications that come with + free-threading. Failure to preserve isolation will expose you to the + full consequences of free-threading, including races and + hard-to-debug crashes. + +This PEP will enhance sub-interpreters so that immutable objects can be +shared directly. The technical aspects of making this possible will be +discussed further down in this document, but in essence, the fact that +an object is immutable permits the object to safely forego isolation and +be accessed outside of the protection offered by a single a GIL, and its +memory managed safely without using the sub-interpreters’ cycle +detectors. This is not the case for mutable objects, and if a mutable +object could be accessed by multiple sub-interpreters, the Python VM +could crash or be susceptible to use-after-free bugs that could corrupt +data silently. If immutability could be circumvented, the same would be +true for immutable objects. This motivates a rather strict +interpretation of immutability, where the mutable and immutable “worlds” +are kept apart. (Although see esacpe hatches below.) + +This explains (at a high-level) why an immutable object may only refer +to other immutable objects. Recall that all mutable objects live inside +their creating sub-interpreter. Assume it was possible to share an +immutable object (including function) with a reference to a mutable +object O in one sub-interpreter, Sub 1, with another sub-interpreter, +Sub 2. Now both Sub 1 and Sub 2 can access the shared mutable object – +Sub 1 uses its GIL to ensure that manipulations of O are carried out +correctly, while Sub 2 uses its GIL. Since these GIL’s are different, +operations that must be atomic may in fact not be. + +The picture below shows the situation above pictorially – the boxes +labelled Sub 1 and Sub 2 show the heaps of sub-interpreters 1 and 2. +Objects A and D are mutable and reside in the heap of Sub 1. Object B is +mutable and resides in the heap of Sub 2. A and B both point to an +immutable shared object C. A sub-interpreter assumes that accesses to +the objects in its heap are protected by its GIL. Note that object C +does not belong to either sub-interpreter, which is why it is drawn +outside of their heaps. **Note that the reference +from C to D is not legal in this PEP, and this example shows what +happens if it was allowed.** The colours on the dashed arrows show which +sub-interpreter is using a reference to access an object. We annotate +the accesses with what GIL is used to synchronise actions on the object. +Because of the reference from C to D, it is possible to have two +accesses relying on different GILs for correctness, meaning +these accesses do not synchronise. This can cause objects +to become prematurely collected, etc. If we forget about +cycle detection, the problem with the different GILs not +synchronising can be mitigated by very stringent locking in +the program around accesses to D (that notably may **not** +permit multiple concurrent **readers** since this this +could lead to a race on reference count manipulations), but +now improper locking can lead to corrupting memory and/or +crashing the interpreter, which is unacceptable. + +.. figure:: pep-0795/diagram_1.svg + + **Figure 1:** Illegal reference from immutable to mutable object. The + immutable object C is shared between two sub-interpreters, and keeps an + illegal reference to a mutable object on the heap of one of the + sub-interpreters. + +In a nutshell, to make objects sharable directly across +sub-interpreters, we must ensure that accesses to shared objects do not +need synchronisation. This in turn means that we cannot rely on normal +cycle detection for immutable objects, unless we stop all +sub-interpreters to collect garbage. To avoid such pauses, this PEP will +instead remove immutable objects from cycle detection. This can be done +without memory leaks or giving up on promptness of reclamation. + +Semantics of immutability +========================= + +This PEP distinguishes between objects which are **mutable**, +**immutable**, or **freezable**. Mutable objects can be updated and +reference both mutable and immutable objects. Immutable objects cannot +be updated, and may only point to other immutable objects. Freezable +objects behave like mutable objects until they are frozen; after that +point they become immutable objects. + +Sometimes it may be necessary for an immutable object to point to +mutable data or support some limited form of mutation. This will be +supported through escape hatches which are described `further down in +this document `_. + +This section proceeds by introducing three stages of increasing support +for making objects immutable, where each stage builds on the previous. + +Stage 1 – inherently immutable objects +-------------------------------------- + +In stage 1, we align the deep immutability of this PEP with the shallow +immutability in Python. All types that are immutable in Python 3.14 are +also deeply immutable in the sense of this PEP. Further, all instances +of ``int``, ``float``, ``str``, ``complex``, and ``bool`` and the +``None`` constant are deeply immutable. Instances of composite objects +like ``tuple``, named tuple, ``frozenset``, ``range`` and ``slice`` are +deeply immutable if their nested objects are deeply immutable. + +In this stage, immutability is always established at the point of +creation, which means that there is no need for an operation that takes +a mutable object and makes it immutable (this is necessary in stage 2 +and 3). + + +.. code-block:: python + :caption: **Listing 1:** Creating immutable (and one mutable) objects. + + # is_immutable(obj) returns True if obj is deeply immutable + from immutable import is_immutable + + # Creates immutable object -- all subobjects are immutable + p = ("this", 15, "an", "ex parrot") + is_immutable(p) # True + + # Does not create an immutable object -- dict is mutable so n is shallow immutable + n = ({'x' : 'parrot'}, None) + is_immutable(n) # False + + from collections import namedtuple + Person = namedtuple('Person', ['name']) + + # Create deeply immutable tuple of named tuples + monty = (Person("Eric"), Person("Graham"), Person("Terry")) + is_immutable(monty) # returns True -- all subobjects are immutable + +For clarity, while all of the objects above except for the dictionary +are de-facto immutable today in Python, these cannot be safely shared +across sub-interpreters without the changes proposed by this PEP. As the +``n`` tuple contains a mutable dictionary it is **not** deeply immutable +and therefore not safe to share between sub-interpreters even with the +changes this PEP proposes. + +Sharing of types +~~~~~~~~~~~~~~~~ + +As all immutable objects’ types are also immutable, they can be shared +across sub-interpreters, and an object’s ``__class__`` references +another immutable object. This is consistent with the definition of deep +immutability – as soon as we follow a reference from a mutable object +inside a sub-interpreter’s heap to an immutable object, we leave the +sub-interpreter’s heap, and there are no references that we may follow +that lead back to a sub-interpreter heap. + +.. figure:: pep-0795/diagram_2.svg + + **Figure 2:** An immutable instance C and its immutable type D being + shared across two sub-interpreters. + +The figure above introduces our drawing notation. The boxes “Sub 1” and +“Sub 2” are the heaps of the sub-interpreters. A and B are mutable +objects living in the isolated heaps. C and D are immutable objects +living outside the sub-interpreter heaps, and are accessible by all. +Arrows are references. + +Dealing with cycles +~~~~~~~~~~~~~~~~~~~ + +When objects are immutable at creation, immutable object graphs cannot +contain cycles. Therefore, immutable objects do not need to participate +in cycle detection. This is important, as each sub-interpreter operates +under the assumption that the objects traversed by its cycle detector +are not mutated by program threads while the cycle detector is running. +While making it impossible to have immutable cycles is limiting the +power of immutability, it avoids a technical problem in memory +management. + +Summary +~~~~~~~ + +- A deeply immutable object may only point to other immutable objects + (modulo escape hatches discussed below), including its class object +- Deeply immutable objects can be created from objects which are + already immutable in Python today – note that for tuples, named + tuples and frozen sets, this require that their constituent parts are + deeply immutable too +- Immutable objects are always immutable at the point of creation +- Immutable object graphs are tree shaped + +Stage 2 – supporting user-defined types and freezing mutable isolated subgraphs +------------------------------------------------------------------------------- + +Stage 2 adds support for immutable user-defined types and function +objects and freezable instances of user-defined types. Instances of +immutable types are freezable, meaning they are mutable, but can be made +immutable by freezing them through an explicit call to a ``freeze()`` +function. We also make the types ``list`` and ``dict`` immutable and +their instances freezable, meaning lists and dicts are mutable on +creation but can be made immutable later. + +An immutable function is a normal function that can be +passed both mutable and immutable arguments, and is free +to mutate any mutable arguments -- but it may not capture a +reference to mutable state as part of the function object. + +An immutable type may not capture mutable state, and additionally does +not permit adding, removing or changing functions. Immutable types may +not inherit from mutable types, but may have mutable subtypes. + +Further down in this document, we will discuss escape hatches that relax +the restrictions on capturing mutable state in functions and types. Note +that while we did not discuss immutable types and functions much in +stage 1, they already exist there, but since these are functions that +are part of core Python, it is easy to ensure that these are +well-behaved with respect to this PEP. + +With freezable objects and a ``freeze()`` function comes the issue of +*freeze propagation*, meaning what freezable objects can be made +immutable as a side-effect of a call to ``freeze()``. To limit freeze +propagation, an object graph can only be made immutable if it is +**self-contained**, meaning there are no references into the object +graph from outside the object graph, except the reference passed to +``freeze()``. For example, ``freeze(x)`` below will fail because of the +reference to ``D`` in ``y``. However, if that reference is removed, or +if ``D`` was already immutable, ``freeze(x)`` will succeed. Note the +cycle between A and B – immutable are no longer neccessarily tree +shaped. + +.. figure:: pep-0795/diagram_3.svg + + **Figure 3:** Explaining the meaning of self-contained object graphs in + freezing. + +In other words, freezing requires that all incoming references to +objects that will become immutable as a result of a call ``freeze(x)`` +originate from the object graph rooted at ``x``. This ensures that a +mutable object will not suddenly become immutable “under foot”. After an +object of type T has been made immutable, subsequent attempts to write +to its fields will result in “TypeError: object of type T is +immutable”.) + +Note that in stage 2, types and functions are either inherently +immutable or inherently mutable (at creation). Freezing objects can +never lead to types or functions becoming immutable. By extension, that +means that objects with mutable types cannot be made immutable +themselves, as each object has a reference to its type. + +To declare an immutable function or type we use a ``@immutable`` decorator, +which will be explained below. Immutable functions are necessary as type +objects typically consist mostly of function objects. + +The major challenge with immutable declarations can be illustrated +easily through an example. What if the following program was legal? + +.. code-block:: python + :caption: **Listing 2:** An illegal immutable function. + + import random + from immutability import immutable, is_immutable + + @immutable + def die_roll(): + return random.randint(1, 6) # captures external random object + + is_immutable(die_roll) # True in this hypothetical example + send_to_other_sub-interpreter(die_roll) # Problem + +The ``die_roll()`` function above captures the ``random`` module object +of its defining sub-interpreter. If we pass the ``die_roll`` function +object to another sub-interpreter, we have successfully recreated the +problematic situation in Figure 1 where C is ``die_roll`` and D is +``random``. **In stage 2, a function which is declared @immutable may +only capture immutable objects.** The code above will raise an exception +saying that ``die_roll()`` cannot be made immutable. Note that freezing a module +object is not possible in stage 2 since the ``module`` type object is mutable. This +is not ideal, but unavoidable for now. Later, we will show how escape +hatches can be used to permit the code above to work by using a proxy +for the ``random`` module that directs calls to ``randint()`` to the +correct sub-interpreter. + +When a type is declared ``@immutable``, all its containing methods are +implicitly declared ``@immutable`` as well. + + +.. code-block:: python + :caption: **Listing 3:** A valid immutable class. + + from immutability import freeze, immutable, is_immutable + + @immutable + class Die: + def __init__(self, sides=6): + self.set_sides(sides) + def set_sides(self, sides): + self.sides = sides + def roll(self): + # Clunky but just to illustrate that this is OK + import random + return random.randint(1, self.sides) + + is_immutable(Die) # True + is_immutable(Die.roll) # True + + d = Die(6) + is_immutable(d) # False + d.roll() # will return a number in [1,6] + d.change_sides(12) # OK + + freeze(d) # turns the object d points to immutable + is_immutable(d) # True + d.roll() # will return a number in [1,12] + d.change_sides(6) # will raise an exception + +Listing 3 creates a ``Die`` type which is immutable at creation. Neither +the ``Die`` class nor its functions capture any external mutable state, +so this declaration is valid. The import inside of ``roll()`` is clunky +but illustrates the major difference between the function importing the +current sub-interpreter’s ``random`` module on each call and a function +capturing and always calling into a specific sub-interpreter’s random +module. The default ``sides`` argument in ``__init__`` is supported +since the value is immutable. + +Right before ``freeze(d)``, we have the following object graph (with +some simplifications to reduce clutter – recall that immutable objects +can only reference other immutable objects). + +.. figure:: pep-0795/diagram_4.svg + + **Figure 4:** Before freezing ``d`` – immutable objects drawn in “ice + blue” and references from immutable objects drawn in blue. + +Note that the instance of ``Die`` pointed to by ``d`` is a normal +mutable Python object. Thus we are allowed to change the number of sides +from 6 to 12. However, after we freeze the object, an attempt to change +its sides will raise an exception, since the object is immutable. Note +that freezing ``d`` will not prevent the value stored in the ``d`` +variable to change. However, as indicated by the blue reference arrow, +``sides`` inside the immutable ``Die`` instance is fixed for life. + +.. figure:: pep-0795/diagram_5.svg + + **Figure 5:** Right after freezing ``d`` – immutable objects drawn in + “ice blue” and references from immutable objects drawn in blue. + +Note that freezing is *in-place*; ``freeze(obj)`` freezes ``obj`` and +for convenience also returns a reference to (now immutable) ``obj``. + +A note on immutable functions is in order. An immutable function that +captures variables from an enclosing scope will not prevent reassigning +those variables, but the function will not be affected: + +.. code-block:: python + :caption: **Listing 4:** + + x = 42 + @immutable + def foo(): + return x + + is_immutable(foo) # True + foo() # returns 42 + x = 4711 # OK + print(x) # prints 4711 + foo() # returns 42 + +.. _summary-1: + +Summary +~~~~~~~ + +In addition to stage 1: + +- Declarations (types and functions) can be made immutable at creation +- Immutable declarations may not capture references to mutable state +- An immutable class’ functions are all immutable, and methods cannot + be added, removed, or changed +- Instances of immutable types are mutable at creation but can be made + immutable +- Making a mutable object graph immutable fails if the object graph is + not self-contained +- Making an object immutable blocks subsequent mutation of the object + +Stage 3 – more dynamic freezing to permit monkey patching +--------------------------------------------------------- + +Stage 3 adds support for freezable types and functions, and adds new +rules for how freezing can propagate. In particular, declarations can be +given explicit permission to propagate to objects through white-listing; +also freezing a function object is permitted to freeze other function +objects allowing entire call chains to be frozen by a single call to +``freeze()``. + +As a companion to the ``@immutable`` decorator, stage 3 adds a +``@freezable`` annotation which permits the creation of mutable classes +and functions, which may be “monkey-patched” (methods added or removed, +fields added or removed, etc.) before eventually becoming immutable. It +also adds an ``@unfreezable`` decorator to explicitly opt-out of support +for freezing. In stage 3, the `module` type object is +immutable. A module may declare all its members freezable +by setting a ``__freezable__`` field to the value ``1``. +To permit a declaration to freeze state in a variable +that it captures, the declaration must be ``@immutable`` or +``@freezable``, and the decorator must be passed the name of +the variable as an argument. + +.. code-block:: python + :caption: **Listing 5:** Freezing objects. + + @freezable + class Person: + def __init__(self, name): # "inherits" @freezable from Person + self.name = name + + monty = [Person("Erik"), Person("Graham"), Person("Terry")] + is_immutable(Person) # False + is_immutable(monty) # False + + freeze(Person) + is_immutable(Person) # True + is_immutable(monty) # False + monty[0].name = "Eric" # OK + + freeze(monty) + is_immutable(Person) # True + is_immutable(monty) # True + + monty.append(Person("John")) # throws exception because monty is immutable + monty.pop() # --''-- + + monty[0].name = "John" # throws exception because all person objects + # in monty are immutable too + +Making an object immutable means that subsequent attempts to write to +its fields will raise an exception. (The attempt to append or pop above +will both result in ``TypeError: object of type list is immutable``.) As +in stage 1 and 2, immutability is deep. We will use the following +running example to explain what happens when we freeze types and +functions in stage 3. We start by explaining the simplest and most +permissive model of freezing, and later discuss how to limit how +freezing may propagate through a program. + +.. code-block:: python + :caption: **Listing 6:** Fraction class. + + ... + + __freezable__ = 1 # make gcd, print_fraction and Fraction @freezable + + def gcd(a, b): + while b: + a, b = b, a % b + return a + + def print_fraction(f): + counter += 1 + print("Fraction: {f} (fractions printed in total: {counter})") + + class Fraction: + def __init__(self, numerator, denominator): + d = gcd(numerator, denominator) + self.n = numerator // d + self.d = denominator // d + + def __add__(self, other): + num = self.n * other.d + other.n * self.d + den = self.d * other.d + return Fraction(num, den) + + def __repr__(self): + return f"{self.n}/{self.d}" + + f1 = Fraction(1, 3) + f2 = Fraction(2, 7) + freeze(Fraction, f1) # freeze class and f1 instance + f1 = f1 + f2 + +Let us first focus on “normal Python objects” that the user has +explicitly created, meaning we ignore “declaration objects” such as +functions and types. We will use the same drawing notation as in +previous figures. + +Right before freezing, we have the following object graph. + +.. figure:: pep-0795/diagram_6.svg + + **Figure 6:** Right before ``freeze(Fraction, f1)``. + +After we have executed ``freeze(Fraction, f1)``, the “ice blue” objects will have +been made immutable: + +.. figure:: pep-0795/diagram_7.svg + + **Figure 7:** Right after ``freeze(Fraction, f1)``. + +Lines drawn in blue denote references that are stored in a field of an +immutable object. Thus, the contents of ``f1.n`` and ``f1.d`` cannot +change, but the stack variable ``f1`` can be made to point to an +entirely different object. (As happens in the next line of the example +``f1 = f1 + f2``.) + +Let’s now bring in functions, modules, and types. To reduce clutter, we +will not draw the full object graph, since there are lots of other +default functions e.g. \ ``__eq__`` in every type, etc. So with some +simplifications, the object graph of our example above looks like this +right before freezing: + +.. figure:: pep-0795/diagram_8.svg + + **Figure 8:** Almost full object graph, right before freezing. + +Note the line from ``Function 3`` (``Fractions.__init__``) to +``Function 1`` (``gcd``). This is the reference that ``__init__`` +captures to the declaration of ``gcd`` in the enclosing state. If +``gcd`` was the result of an import, the result would have been the +same. + +To see what should be the effect of successfully freezing, we can walk +the object graph from the starting point of the call to ``freeze()`` and +follow all outgoing references and freeze all mutable objects that we +discover, and continue until there are no more mutable objects to +freeze. Here is the result: + +.. figure:: pep-0795/diagram_9.svg + + **Figure 9:** Almost full object graph, right after freezing. + +In the initial version of this PEP, ``freeze(f1)`` would have sufficed +to freeze the above. However, to limit freeze propagation, we do no +longer permit freezing of objects to propagate to freezing types. +Hence the ``freeze(Fraction, f1)`` above. (The order of +the two arguments is insignificant, but if we split the call +into two, order matters: freezing ``f1`` before ``Fraction`` +would not work as the first call to freeze would fail +because the ``Fraction`` type is mutable.) + +When the ``Fraction`` class is made immutable all its function objects, +such as ``__init__``, ``__add__``, and ``__repr__`` must be immutable +too, or they are no longer callable. Of the three functions in +``Fraction``, only ``__init__`` captures external state: a reference to +``gcd``. This means that the ``gcd`` function must be made immutable +too. Notably, ``__add__`` has a reference to ``Fraction`` which would +also have to be made immutable, but is alredy immutable in this example. +(It’s becoming immutable is what causes ``__add__`` to become immutable +in the first place.) + +Note that the ``gcd`` variable in the stack frame did not become +immutable, although it is pointing to an immutable object. It is still +possible to reassign that variable. Also note that while a Python class +technically has a reference to all its subclasses, we do not freeze +subclasses, only superclasses, when a class is immutable. We will return to +this later and explain when it is possible to make exceptions such as +this one. + +Let us revisit the immutable ``foo`` function from stage 2 but use the +``@freezable`` annotation to show the effect of delaying freezing until +an arbitrary point later in the program: + +.. code-block:: python + :caption: **Listing 7:** + + x = 42 + @freezable + def foo(): + return x + + is_immutable(foo) # False + foo() # returns 42 + x = 4711 # OK + print(x) # prints 4711 + foo() # returns 4711 + + freeze(foo) + is_immutable(foo) # True + x = 42 # OK + print(x) # prints 42 + foo() # returns 4711 + +.. _summary-2: + +Summary +~~~~~~~ + +In addition to stage 2: + +- Support for freezable types and functions that permits delaying + freezing until after monkey patching +- Making a freezable class immutable makes its functions and any class + state immutable, and blocks changes to the class; functions that + could not be made immutable are no longer callable +- A module may declare all its members freezable + +Escape hatches +============== + +Deep immutability can sometimes be too strict. (Examples of this has +come up in DPO discussions – for example, a class might use a mutable +cache internally, even though all its instances are technically +immutable.) To this end, we provide two escape hatches, both in the form +of a field that stays mutable even when the object containing the field +is immutable: + +1. **Shared fields** which can only hold immutable objects. +2. **Interpreter-local fields**, which may hold both mutable and + immutable objects. + +A shared field’s value is visible to all sub-interpreters that read the +field. Since only immutable objects can be shared across +sub-interpreters, that means that shared fields can only contain +immutable objects. This is checked by the field on assignment, and +attempts to store a mutable objects in a shared field throws an +exception. The field takes care of synchronisation if multiple +sub-interpreters read or write the field at the same time, and ensures +that reference count manipulations are correctly handled. + +An interpreter-local field ``f`` transparently behaves as multiple +fields, one per sub-interpreter in the program, and each sub-interpreter +will only ever read or write “its field”. This ensures that two +sub-interpreters accessing the same field concurrently will not race on +the value in the field, since they are accessing different objects. When +a mutable value is stored in an interpreter-local field, it will only be +accessible to the sub-interpreter that stored it. Thus, supporting +mutable values is safe. + +Shared fields +------------- + +Shared fields are implemented as an object indirection. The shared field +is part of the ``immutable`` module that this PEP provides. Here is an +example that shows what programming with a shared field might look like. +The example shows a class maintaining a mutable instance counter, that +keeps working even after the class is made immutable. + +.. code-block:: python + :caption: **Listing 8:** Cell implemented using a shared field. + + import immutable # library this PEP provides + + class Cell: + counter = immutable.shared(0) + + def __init__(self, a): + self.value = a + while True: + old = self.__class__.counter.get() + new = old + 1 + immutable.freeze(new) # shared fields can only hold immutable objects + if self.__class__.counter.set(old, new): # stores new in counter if counter's value is old + return # break out of loop on success + + def __repr__(self): + return f"Cell({self.imm}) instance number {self.__class__.counter.get()})" + + c = Cell(42) + immutable.freeze(c) # Note: freezes Cell + immutable.is_immutable(Cell) # returns True + print(c) # prints Cell(42) instance number 1 + d = Cell(4711) + print(d) # prints Cell(4711) instance number 2 + +Note that in free-threaded Python, it would be technically safe to +permit a shared field to store mutable objects, as the problem with +multiple sub-interpreters accessing a mutable value under different GILs +does not exist. However, we believe in keeping the programming model the +same regardless of whether sub-interpreters or free-theading is used. +(Programming with immutable objects is also less prone to subtle +errors.) + +Let’s use the same diagrams as when explaining the problem with having a +reference to mutable state from immutable state above, to show how the +shared field is different. Let us again use two sub-interpreters that +both have a reference to a shared immutable counter declared as above: + +.. figure:: pep-0795/diagram_10.svg + + **Figure 10:** Shared field. + +Notably, there are no references from immutable state to mutable state +inside a sub-interpreter, which we have seen causes problems. While the +shared field object poses as an immutable object in the system, it is +really mutable, which is why it is drawn in gray. As it uses its own +synchronisation internally, and only manipulates immutable objects, it +is not a problem that concurrent accesses do not synchronise with each +other (which they don’t since they use different GILs to synchronise). + +Interpreter-local fields +------------------------ + +Interpreter-local fields are analogous to ``threading.local()`` in +Python, but keeps one value per interpreter, as opposed to one value per +thread. Thus, if two different sub-interpreters read the same field, +they may read different values; two threads in the same sub-interpreter +will always read the same value (provided there has been no interleaving +mutation). + +Interpreter-local fields can store both mutable and immutable objects. +In the case of a mutable object, this object will be guaranteed to live +on the heap of the sub-interpreter that accesses the field. It is +therefore safe to store mutable objects in such a field. + +The ``immutable`` module contains the class for interpreter-local +fields. Here is what programming with such a field might look like: + +.. code-block:: python + :caption: **Listing 9:** Cache in prime factorised implemented using an interpreter-local field. + + import immutable # library this PEP provides + + class PrimeFactoriser: + def __init__(self): + self.cache = immutable.local(freeze(lambda: { 2: [2], 3: [3], 4: [2, 2] })) + def factorise(self, number): + if self.cache.has_key(number): + return self.cache[number] + else: + factors = ... # perform calculation + self.cache[number] = factors + return factors + + pf = PrimeFactoriser() + immutable.freeze(pf) + pf.factorise(7) # will update the cache as side-effect (on the current interpreter) + +The example above maintains a mutable dictionary as part of a cache. +Despite ``pf`` being immutable, we can still mutate the cache, but the +mutations and the cache are only visible on the current interpreter. +Another interpreter trying to factorise 7 will have to redo the +calculations and populate its own cache. (The immutable lambda function is +used to initialise the local storage on each sub-interpreter on first +access.) + +While interpreter-local fields cannot be used to implement a global +instance counter, we can use a shared field to implement the caching. +Since a shared field cannot hold mutable objects, we would have to +freeze the dictionary before storage, and to update the cache we would +have to first make a mutable copy of the current cache, add to it, and +then freeze it again before storing it back into the field. On the other +hand, we only need to cache prime factors once as opposed to +once-per-interpreter, as the cache is global. + +We can illustrate the difference between the interpreter-local escape +hatch and shared fields pictorally: + +.. figure:: pep-0795/diagram_11.svg + + **Figure 11:** Interpreter-local field. + +The interpreter-local field ensures that accesses from Sub 1 yield the +reference to E, whereas accesses from Sub 2 yield the reference to F. +Thus, all accesses to a mutable object on one interpreter’s heap is +always synchronising on the same GIL. + +As one more example of how shared fields and interpreter-local fields +complement each other, we revisit the list of references from a +superclass object to its subclasses that we are not freezing. We can +implement this using a shared field in combination with an +interpreter-local field. Consider the immutable class A, to which we +want to add a new *immutable* subclass B and a new *mutable* subclass C. +Since immutable subclasses are shared, we add a shared field with an +immutable list of references to immutable subclasses. Every time we add +to that list, we create a new list from the old, add the new reference, +freeze the new list and stick it back into the shared field. In contrast +to B, the mutable subclass C should only be visible to the +sub-interpreter that defined it. Thus, we use an interpreter-local field +to keep a (mutable) list of the mutable subclasses of A. Together, these +two lists store the subclasses of a class. + +Initialisation of interpreter-local fields +------------------------------------------ + +Interpreter-local fields can hold mutable objects which can only be +initialised from the interpreter to which the field belongs. To permit +the interpreter that defines the field to control the initialisation of +the field, the constructor ``local`` accepts an immutable function object as +input. The function gets the interpreter-local field as argument and can +install (possibly mutable) values. Here is an example: + +.. code-block:: python + :caption: **Listing 10:** Initialising an interpreter-local field. + + from immutable import local + sharable_field = local(freeze(lambda: 0)) + +The first time the sharable field is loaded by a sub-interpreter, that +sub-interpreter will call the lambda function and store its result in +the value of the local field for that sub-interpreter. (If the initial +value is an immutable object, one could also consider passing in the +object straight, rather than a function that returns it. However, local +fields are very likely to be rare enough that this extra finger typing +is not a problem.) + +Escape hatches and modules +========================== + +Let us come back to modules. Assume that the ``gcd`` function in the +fractions example from stage 3 was imported from the module +``useful_stuff`` like so: ``from useful_stuff import gcd``. In this +case, ``Fraction.__init__`` would capture just the ``gcd`` function +object which would be made immutable if we freeze the ``Fraction`` +class. + +Let us see what would happen if ``gcd`` had been called from +``__init__`` like this: ``useful_stuff.gcd()``? While this is not very +different from the less common form above, the ability to reliably +analyse Python code without access to the source stops at capturing +state, which can be queried directly from the function object. Thus, we +have no other option than to freeze the module object, which will +propagate to ``gcd``. This is not a perfect solution. + +Luckily, the interpreter-local field permits an immutable object to +store pointers to mutable objects without compromising safety in the +sub-interpreters model. This can be used together with modules and +functions to permit an immutable function to call functions that rely on +mutating state. For example, let us define a module for logging thus: + +.. code-block:: python + :caption: **Listing 11:** Running module example. + + # logger.py + messages = [] + + def log(msg): + messages.append(msg) + + def flush(file): + file.writelines(messages) + messages.clear() + +And let’s use the module: + +.. code-block:: python + :caption: **Listing 12:** Running module example – use-site. + + import logger + + def simulate_work(): + logger.log("simulate") + + for _ in range(0, 10): + simulate_work() + + with open("log.txt", "w") as f: + logger.flush(f) + +If we wanted to freeze ``simulate_work()`` and pass it around so that +any sub-interpreter could call it, we have to do some refactoring of the +module first. For example, it is not thread-safe right now, meaning that +concurrent calls to log could drop some messages, etc. But more +importantly, it is not safe for different sub-interpreters to manipulate +the same mutable ``messages`` list object. + +Let’s go through our options. For completeness, we start with some +options that do *not* rely on escape hatches. These all involve +rethinking the ``logger`` design. + +Do nothing +---------- + +While this is not an option here, for completeness, let us explore doing +nothing. If we simply make ``logger`` immutable, the ``messages`` list +becomes immutable and calls to ``log`` will result in exceptions on +every attempt to append to ``messages``, which means we have +“incapacitated the module”. For a module which is stateless, or that +only had immutable constants, this would have worked. + +Make the module stateless +------------------------- + +We can refactor the module to become stateless: + +.. code-block:: python + :caption: **Listing 13:** Stateless logger module. + + # logger.py + + def log(msg): + print(msg) + + def flush(file): + """Deprecated, should no longer be used""" + pass + +This is probably not what we want to do, but shows that printing from an +immutable function is not a problem (because the ``print`` method is +considered immutable in this PEP). This strategy might work in cases that +can be rewritten in terms of immutable builtins, but is not a general +solution. + +Move the module’s state out of the logger module +------------------------------------------------ + +We can refactor the module to use external state which is passed in to +the logger. The code below permits the module to be used as before, but +now switches behaviour to rely on the user passing in a mutable list to +``log`` and ``flush`` if ``messages`` are immutable. + +.. code-block:: python + :caption: **Listing 14:** Logger module with external state. + + # logger.py + from immutable import is_immutable + messages = [] + + def log(msg, msgs=None): + if is_immutable(messages): + if msgs is None: + raise RuntimeError("Nowhere to log messages") + else: + msgs.append(msg) + else: + messages.append(msg) + + + def flush(file, msgs=None): + if is_immutable(messages): + if msgs: + file.writelines(msgs) + msgs.clear() + else: + file.writelines(messages) + messages.clear() + +This is a rather large refactoring, and probably not what we want in +this case, but maybe in others. + +The remaining cases use our escape hatches to permit the module to hang +on to some mutable state. + +Move the module’s state out of sub-interpreter isolation +-------------------------------------------------------- + +Keeping the module’s state but moving it out of sub-interpreter +isolation requires that all objects in the state, except for the escape +hatch, are immutable. + +.. code-block:: python + :caption: **Listing 15:** Logger module with shared field. + + # logger.py + from immutable import shared, freeze + messages = shared(freeze([])) + + def log(msg): + new_messages = messages.get()[:] + new_messages.append(msg) + freeze(new_messages) + messages.set(new_messages) + + def flush(file): + file.writelines(messages.get()) + messages.set(freeze([])) + +This module can now be made immutable without incapacitating it – the +``messages`` variable will effectively remain mutable (through an +indirection), and can be updated with new messages. Importantly, there +will now only be a single logger shared across all sub-interpreters. (To +that end, we should add some synchronisation to ``log`` and ``flush`` +but that is standard concurrency and not specific to this PEP. On a +related note, locks are considered immutable so pose no problem – +imagine implementing them using a shared field to get an idea of how +they could work.) + +Keep one logger per sub-interpreter +----------------------------------- + +If we have a multi-phase initialization module, it may make more sense +to have one logger state per sub-interpreter. There are two ways to go +about this. Let’s start with the analog of the above solution using an +interpreter-local field. + +.. code-block:: python + :caption: **Listing 16:** Logger module with interpreter-local field. + + # logger.py + from immutable import local + messages = local(freeze(lambda: [])) + + def log(msg): + messages.append(msg) + + def flush(file): + file.writelines(messages.get()) + messages.set([]) + +The interpreter-local field is initialised on first access using a +immutable lambda function. The function needs to be immutable to be shared +across sub-interpreters. When the function is called it creates a +**mutable** empty list which is stored as the initial value of the +current sub-interpreter’s ``messages`` field. + +We do not need to change ``log`` and only change ``flush`` to call +``set()`` and ``get()`` on the messages field – the logic is otherwise +unchanged. Now freezing log and flush is unproblematic as freezing does +not propagate through ``messages``. A call to the shared ``log`` +function from a sub-interpreter will store the log message on that +sub-interpreter’s ``message`` list. + +Keep one logger per sub-interpreter – take 2 +-------------------------------------------- + +We can achieve the same effects as above without changing the logger +module, but instead change how we import it. Let’s first do that +manually, and then introduce some tools that are part of the +``immutable`` library in this PEP. + +.. code-block:: python + :caption: **Listing 17:** Sketching support for wrapping modules behind immutable proxies. + + @immutable + def import_and_wrap(module): + from immutable import local + + @immutable # note -- assumes module is immutable + def local_import(): + return __import__(module) + + return local(local_import) + + logger = import_and_wrap("logger") + # everything below unchanged + + def simulate_work(): + logger.log("simulate") + + for _ in range(0, 10): + simulate_work() + + with open("log.txt", "w") as f: + logger.flush(f) + +The ``import_and_wrap`` function wraps the module object for the logger +module in an interpreter-local field. Thus, ``logger`` will not be +made immutable when we freeze ``simulate_work``. The first time a +sub-interpreter tries to access the shared ``logger`` object as part of +a call to ``logger.log()`` inside ``simulate_work``, the sub-interpreter +will import the module and subsequent calls on the local field will be +forwarded to the module object. + +To ensure that any library that imports ``logger`` automatically gets +the wrapper, it is possible to replace the entry in +``sys.modules['logger']`` with the wrapper. The ``immutability`` library +in the PEP provides utilities for importing and wrapping, wrapping an +already imported module, and ensuring that subsequent ``import`` +statements import the wrapper. + +The ``immutable`` module provided by this PEP contains one function for +wrapping a module object in an immutable proxy and another function for +installing a proxy in ``sys.modules`` so that subsequent ``import`` +statements get the proxy. + +Controlling the propagation of freezing +======================================= + +A recurring theme when discussing this proposal on DPO has been concerns +that freezing an object will propagate beyond the intension, and cause +objects to be made immutable accidentally. This is an inherent effect in +immutability systems at witnessed by e.g. ``const`` in C and C++. +Annotating a variable or function with ``const`` typically propagates in +the source code, forcing the addition of additional ``const`` +annotations, and potentially changes to the code. In C and C++, this +happens at compile-time, which helps understanding the propagation. (See +also the section on static typing for immutability later in this +document.) + +Freeze propagation in stage 1 +----------------------------- + +The stage 1 support for immutability only supports immutable objects +which are constructed from de-facto immutable objects in Python 3.14. As +objects can only be immutable at creation-time, there is no freeze +propagation. Object graphs must be constructed inside out from immutable +building blocks. This can be cumbersome, but the result is never +surpising. + +This will allow sub-interpreters to immutably share things like strings, +integers, tuples, named tuples etc. This is expressive enough to for +example express JSON-like structures, but notably does not support +sharing arbitrary objects of user-defined type, and not functions. + +**Propagation rules:** + +- There is no such thing as freeze propagation. Objects are immutable from + the leaves up, at construction-time. There is no ``freeze()`` + function. + +**Freezing rules:** + +- An object which is an instance of a type that is de-facto immutable + in Python 3.14 is immutable at creation; unless it references data + that is not immutable. Notable exception: instances of ``type`` + create mutable objects; only the type objects we have explicitly + listed are immutable. + +**Immutability invariant:** + +- An immutable object only references other immutable objects. + +Freeze propagation in stage 2 +----------------------------- + +Stage 2 adds support for user-defined immutable types and functions. + +Stage 2 introduces freeze propagation as it adds a ``freeze()`` function +to turn freezable objects immutable. Freezing is only supported for +self-contained object graphs. This ensures that the code in Listing 18 +will never raise an exception due to a mutation error on the last +assignment to ``y.f``. + +.. code-block:: python + :caption: **Listing 18:** In stage 2, freeze propagation cannot affect shared state. + + y.f = 41 + freeze(x) # if succeeds, guaranteed to not have affected y + y.f += 1 + +If freezing ``x`` could propagate to ``y``, then the object graph rooted +in ``x`` is not self-contained, which will cause ``freeze(x)`` to fail. +Similarly, since passing a reference to a function guarantees that the +reference at the call-site remains, a function cannot freeze its +arguments. Notably, this avoids freezing accidentally incapacitating a +module. Freezing a list object that happens to be part of a module’s +state that should stay mutable will incapacitate the module will fail +because the list is not self-contained. + +This is a guarantee that “cuts both ways”: it is very hard to pass an +object around without making it impossible to freeze. + +**Propagation rules:** + +- Declaring a type as immutable propagates to its functions, but not to + any other types or functions, or non-declaration objects. +- Freezing an object propagates to other objects, but not to + declarations. + +**Freezing rules:** + +- Objects that are instances of immutable types are freezable by + default, but freezing an object graph will fail unless the graph is + self-contained. +- An object can be made impossible to freeze by setting + ``__freezable__ = 0``. + +**Immutability invariant:** + +- An immutable object only references other immutable objects, with the + exception of mutable objects that preserve sub-interpreter isolation + but are nevertheless marked as immutable in the system. (For example + escape hatches.) + +Freeze propagation in stage 3 +----------------------------- + +Stage 3 permits freezable types and functions. To avoid freezing types +and functions rendering them unusable, we permit freezing to propagate +through declarations but not from declarations to objects unless +permission has been explicitly given by the programmer by giving +arguments to ``@immutable`` and ``@freezable``. + +**Propagation rules:** + +- Freezing an object propagates to other objects, but not to + declarations (i.e. types and functions). +- Freezing a function propagates to other functions. +- Freezing a type propagates to its super types and functions in the + type and supertypes. +- Freezing a module object propagates to any object or declaration + reachable from the module object, directly or indirectly. (Notably, + this may include submodules.) +- Freezing a declaration decorated with ``@immutable`` or ``@freezable`` + may propagate to objects (causing them to become immutable). + +**Freezing rules:** + +- Module objects must opt-in to support freezing. +- Freezing a declaration inside a module that does not support freezing + will fail unless the declaration is decorated with ``@freezable``. +- Freezing a declaration that captures mutable state will fail unless + the declaration is decorated with ``@immutable`` or ``@freezable`` that + explicitly name the state becoming immutable. +- Objects “inherit” their support for freezing from its class. This can + be overridden. + +**Immutability invariant:** + +- An immutable object only references other immutable objects, with the + exception of mutable objects that preserve sub-interpreter isolation + but are nevertheless marked as immutable in the system. (For example + escape hatches.) + +Details and discussion +---------------------- + +Freezing objects +~~~~~~~~~~~~~~~~ + +In stage 2 and 3, an object can become immutable if it satisfies *all* of the +constraints below: + +- Its type is immutable +- Is does not have a field ``__freezable__`` with a value other than 1 +- All the objects reachable from the object can become immutable +- All references to this object are stored in objects being made immutable at + the same time as the object (or is the argument to the ``freeze`` + call) + +Failing to satisfy any of the above constraints will cause freezing to +fail, leaving all objects in their original state. + +Freezing functions +~~~~~~~~~~~~~~~~~~ + +A function can become immutable if it satisfies *all* of the constraints below: + +- It is declared in a module that opts-in support for freezing and the + function is not declared ``@unfreezable``, or the function is + declared ``@immutable`` or ``@freezable`` +- All function objects the function captures can become immutable +- The function either does not capture any mutable objects, or it is + declared ``@immutable`` or ``@freezable``, the state that becomes immutable is + in the white list, and those objects freeze successfully. Default + arguments are always permitted to freeze. + +Each of the following functions can be made immutable by a simple call to +``freeze``: + +.. code-block:: python + :caption: **Listing 19:** Examples of freezable functions. + + # opt-in to support freezing the current module + __freezable__ = 1 + + # pure function OK to freeze + def function1(a, b): + return a + b + + # only captures other function so freeze propagates + def function2(a, b): + return function1(a, b) + + x = freeze(something) + # only captures immutable state + def function3(a): + a.append(x) + + # only captures immutable state + def function4(a): + x.append(a) # Note -- will throw exception always when called + +Freezing ``function3`` and ``function4`` will succeed only if the +current value of ``x`` is immutable. Furthermore, it “locks” the value +of ``x`` in the immutable functions, so even if ``x`` is reassigned in the +outer scope, the immutable functions will still see the old immutable value. +If ``function3`` or ``function4`` were declared ``@freezable("x")``, +they would have made the contents of ``x`` immutable. + +Also note that ``function1`` will become immutable as a side-effect of freezing +``function2``. + +The final example shows that freeze propagation can make a function +unusable. However, because of the rules of freeze propagation, +``freeze(function4)`` will not work unless ``x`` is immutable, so a +programmer needs to perform multiple steps to end up in this situation. +To prevent ``function4`` from becoming immutable, we can use the +``@unfreezable`` decorator that the ``immutable`` library provides. + +If class ``Foo`` defines an instance method ``bar`` or a static method +``bar``, then ``Foo.bar`` is a function object. Thus, the following +succeeds: + +.. code-block:: python + :caption: **Listing 20:** Freezing a function object directly. + + # showcase different way of supporting freezing + @freezable + class Foo: + def bar(self): + self.variable = 42 + return self.variable + + freeze(Foo.bar) # succeeds + foo = Foo() + foo.bar() # OK, returns 42 + +Note that ``freeze(foo)`` would subsequently cause ``foo.bar()`` to fail +because ``self`` inside ``foo`` would now be immutable. + +If an immutable function object is bound to a method object, the method +object is mutable, and the “self” object can be mutable too. + +Freezing methods +~~~~~~~~~~~~~~~~ + +Method objects are wrappers for function objects and the object to which +the method is bound, the “self”. A method object can become immutable if the +function **can become** (or is already) immutable, and the self object **is already** +immutable. Thus, the following example will fail to freeze: + +.. code-block:: python + :caption: **Listing 21:** Freezing method objects. + + # opt-in to support freezing the current module + __freezable__ = 1 + + class Foo: + def bar(self): + self.variable = 42 + return self.variable + + foo = Foo() + freeze(foo.bar) # fails because foo is not immutable + +Freezing types +~~~~~~~~~~~~~~ + +A type can become immutable if it satisfies *all* of the constraints below: + +- It is declared in a module that opts-in support for freezing and the + type is not declared ``@unfreezable``, or the type is declared + ``@immutable`` or ``@freezable`` +- All its supertypes can become immutable +- Its meta class can become immutable +- The type either does not define any mutable class state, or it is + declared ``@immutable`` or ``@freezable`` and all mutable objects it + captures can become immutable, and are named by the decorators. + +Note that while functions can be reassigned we do not count this as +class state. We also do not consider implicitly defined mutable state +such as the ``__bases__`` field or the ``__class__`` field. + +Note the absence of a requirement that all functions defined in the +class must be able to become immutable. **If a function fails to freeze, it will not be +possible to call that function on the immutable type.** This alternative is +preferrable to failing to freeze a type if not all its functions can become +immutable. + +Thus, in the example below, ``Foo`` can become immutable, but ``Foo.method1`` +cannot be called from that point on, because the function failed to +freeze. + +.. code-block:: python + :caption: **Listing 22:** Module object freezing. + + # opt-in to support freezing the current module + __freezable__ = 1 + + def function1(a): # can become immutable + return a + + x = [] + def function2(a): # cannot become immutable + x.append(a) + + class Foo(object): + def __init__(self, a): # can become immutable + self.a = function1(a) + def method1(self): # cannot become immutable + function2(self.a) + + freeze(Foo) # OK + foo = Foo() # OK + foo.method1() # raises exception -- method1 not safe to call when Foo is immutable + +Note that a class that defines class state may not be made immutable unless the +class is explicitly declared ``@immutable`` or ``@freezable``. This is to +avoid accidentally incapacitating a class by freezing it. Thus, the +following class cannot be made immutable: + +.. code-block:: python + + # opt-in to support freezing the current module + __freezable__ = 1 + + class Foo: + constant_state = 3.14 + +To permit it to be made immutable, simply opt-in support for immutability +explicitly, for example: + +.. code-block:: python + + @freezable + class Foo: + constant_state = 3.14 + +Or make the class immutable right after declaration: + +.. code-block:: python + + @immutable + class Foo: + constant_state = 3.14 + +Although ``3.14`` was already an immutable object, making the class +immutable prevents reassigning the ``constant_state`` field. By +annotating the class as ``@immutable`` or ``@freezable``, the programmer +explicitly permits turning the mutable field into a constant. + +If the constant state is not an immutable object, an explicit freeze +call is needed: + +.. code-block:: python + + @immutable + class Foo: + constant_state = freeze([3.14]) + +Consequences of this design on freeze propagation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this PEP, freezing a type or function will never propagate to normal +objects in the program, unless the programmer gave explicit permission +to do so by adding a ``@immutable`` or ``@freezable`` decorator. In other +words, freezing such declarations should not lead to accidental freezing +of program state. Freezing a function cannot “escalate” to freeze types +or modules, and freezing a type cannot escalate beyond its supertypes +(without explicit permission through use of a decorator). + +There are two ways to freeze state: + +1. Explicitly call ``freeze`` on a non-declaration object +2. Explicitly call ``freeze`` on a module object + +Because module objects opt-out of freezing by default, it should be hard +to accidentally incapacitate a module. The module has to explicitly turn +on that support. Creating a module with some types or functions that +support freezing is possible by explicitly opting in to freezing in +those declarations. If these declarations capture mutable module state +outside of the permissions given to these declarations, then freezing +will fail. The module implementer needs to either make that state +immutable or use an escape hatch (or increase the permissions). + +Below is an example of a program with some objects and modules with +types, functions and state. We will use this example for illustration. + +.. figure:: pep-0795/diagram_12.svg + + **Figure 12:** Module structure. + +For concreteness, assume that all modules opt-in to freezing, nothing +opts out, and nothing is immutable directly on declaration. Now, +``freeze(y)`` will fail unless ``Module1.Type1`` is immutable. To make +``Module1.Type1`` immutable, we can either do ``freeze(Module1)`` which +will freeze everything in ``Module1`` or we can just do +``freeze(Module1.Type1)``. The latter will attempt to freeze ``Func1`` +which will fail because it captures the state in ``Var1``. We are still +allowed to freeze ``Type1``, but not call any of its methods that call +``Func1``. We could go in and freeze ``Var1`` to resolve this, but we +might be discouraged by code comments, documentation, a “private name” +etc. Freezing ``Module3.Type4`` will freeze ``Module3.Type3``, but +cannot end up freezing ``Func3`` or ``Var3``. Finally, freezing +``Func3`` explicitly cannot propagate through the import to ``Module3`` +since freezing a function cannot escalate to a module (unless ``Func3`` +was declared ``@freezable``). + +Backing up to our initial example with the ``Fraction`` class, here is +how we would have approached freezing ``f1``: + +**Listing 23:** Freezing in steps. + +.. code-block:: python + + # Step 1: Opt in freezing in the current module (__main__) + __freezable__ = 1 + + # Step 2: Freeze the type + # The type must be made immutable. + # Propagates from Fraction to __init__, __add__, and __repr__, + # and from __init__ to gcd. + freeze(Fraction) + + # Step 3: freeze the fraction object + # This freezes Fraction instance 1. The ints 1 and 3 are + # already immutable, and so is the int type. + freeze(f1) + +Dealing with cyclic dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since freezing a type can only propagate to other types that are super +types of the first type, we need a way to deal with cyclic dependencies +such as this: + +.. code-block:: python + :caption: **Listing 24:** Freezing with cyclic dependencies. + + class A: + def foo(self): + self.value = B() + + class B: + def bar(self): + self.value = A() + +Notably, freezing ``A`` freezes ``A.foo`` which captures ``B``. However, +since ``B`` is not immutable, freezing ``A.foo`` will fail according +to the rules above. Trying to first freeze ``B`` does not solve the +problem, as ``B.bar`` fails to freeze. The solution to this problem is +to let ``freeze`` take multiple arguments which can be used to resolve +these kinds of situations: ``freeze(A, B)`` will permit ``A.foo`` to +capture ``B`` because it sees that ``B`` is in the list of things which +will be made immutable. (And if ``B`` would fail for some other reason, the +effects of the entire call will be made undone.) + +For the same reason, we cannot make ``A`` and ``B`` ``@immutable``. Dealing +with cyclic dependencies requires freezing to happen after all classes +involved have been constructed. + +Preventing a freezable instance from becoming immutable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To prevent a freezable object from becoming immutable we can set +``__freezable__ = 0`` (or any other value than 1). The ``immutable`` +module that this PEP provides contains a context manager that one can +use to set ``__freezable__ = 0`` at the start of a block, and restores +it at the end: + +.. code-block:: python + :caption: **Listing 25:** Making objects temporarily unfreezable. + + with immutable.disabled(obj): + # old = getattr(obj, '__freezable__', 1) + # obj.__freezable__ = 0 + ... + call_into_some_library(obj) + ... + # implicitly does obj.__freezable__ = old + +Immutability out-of-the-box +--------------------------- + +This PEP proposes that all types which are already immutable in CPython +are made PEP795-immutable and shared across sub-interpreters. For +clarity, these are: + +- **TODO** @MattJ +- ``int`` +- ``float`` +- ``bool`` +- ``complex`` +- ``str`` +- ``bytes`` +- ``tuple`` (if all elements are themselves immutable) +- ``frozenset`` +- ``range`` +- ``slice`` +- ``dict`` +- ``list`` +- ``NoneType`` (``type(None)``) +- ``ellipsis`` (``type(...)``) +- ``NotImplementedType`` (``type(NotImplemented)``) +- ``code`` (``types.CodeType``) +- ``function`` (``types.FunctionType``) +- ``builtin_function_or_method`` (``types.BuiltinFunctionType``) +- ``method_descriptor`` (e.g. ``str.upper``) +- ``wrapper_descriptor`` (e.g. ``int.__add__``) +- ``member_descriptor`` (e.g. ``__slots__`` members) +- ``staticmethod`` +- ``classmethod`` +- ``property`` +- ``type`` +- ``function`` +- ``object`` + +In addition to these, the following types should support immutability +out-of-the-box: + +- **TODO** @MattJ +- ``fractions.Fraction`` +- … +- ``threading.Lock`` +- ``threading.RLock`` +- ``threading.Semaphore`` +- ``threading.Condition`` +- functools stuff… LRU cachhe +- meta classes like ABCMeta + +Permitting lock objects to be immutable is key to permit concurrent +sub-interpreters to coordinate their actions. While this is not +necessary to avoid data races (modulo shared fields), it may be needed +to correctly capture the intended program logic. + +The ``immutable`` library +========================= + +In this section we describe the ``immutable`` library that contains the +user-facing functions of this PEP. Note that this PEP relies on checking +an object’s immutability status before writes, which requires many +changes to core Python. We annotate each section below with the stage +where each definition is added. + +The ``freeze`` function (stage 2 and 3) +--------------------------------------- + +The ``freeze`` function is arguably the most important function in this +PEP. A call to ``freeze(obj)`` will traverse the object graph starting +in ``obj``; it follows the *propagation rules* to determine how far +freezeing ``obj`` may propagate, and it follows the *freezing rules* to +determine whether an object can become immutable or not. If in the end, ``obj`` +would fail to meet the *immutability invariant*, the entire freeze +operation fails, and ``obj`` is left in state it was right before the +call. + +When an object is immutable, we set a bit in the object header that is used +to track the immutability status of all objects. All writes to fields in +the object are expected to check the status of this bit, and raise an +exception instead of carrying out the field write when the bit is set. + +As part of freezing, we perform an analysis of the object graph that +finds the strongly connected components in the graph that gets immutable. A +strongly connected component is essentially a cycle where every object +can directly or indirectly reach all other objects in the component. +This means that all objetcs in a strongly connected component will have +exactly the same lifetime. This in turns mean that we can use a single +reference count to manage the lifetime of all the objects in the +component. This means that no cycle detection is needed for immutable +objects. + +With respect to the implementation, we will select one object in the +component to hold the reference count, and turn remaining reference +counters into pointers to that object. That means that reference count +manipulations on immutable objects will need one more indirection to +find the actual counter (in the general case). + +The ``is_immutable`` function (stage 1) +--------------------------------------- + +The ``is_immutable`` function inspects the bit in the object header set by +the ``freeze`` function and returns ``True`` if this bit is set. If +called on a shallow immutable object, and the bit is not set, +``is_immutable`` will call ``is_immutable`` on all the members. If the result +is true, it will be “cached” in the object by setting the bit. + +The ``NotFreezable`` type (stage 3) +----------------------------------- + +This is the exception type that ``freeze`` or ``@immutable`` throws when +failing to freeze an object. + +The ``disabled`` context manager (stage 1) +------------------------------------------ + +This is a very simple context manager that adds a field +``__freezable__`` to the object at the start of the block with value 0 +(meaning the object isn’t freezable), and restores the original value at +the end of the block. + +TODO (stage 2 and 3) +-------------------- + +**NOTE: come up with good names** - ``make_module_shared`` - +``import_as_shared`` + +The ``@immutable`` (stage 2), ``@freezable`` and ``@unfreezable`` decorators (stage 3) +-------------------------------------------------------------------------------------- + +The decorator ``@unfreezable`` turns off support for freezing a class or +function. This decorator is only needed when an enclosing scope opts-in +support for freezing. This allows excluding a type from a module when +the module is immutable, or a function from a type when the type is immutable. + +The ``@freezable`` decorator turns on support for freezing a class or +function. When the decorator is used without arguments, it does **not** +permits objects captured by the decorated declaration to be immutable. When +given arguments, it **permits** objects to become immutable. + +The ``@immutable`` decorator behaves exactly like ``@freezable``, except +that is freezes the declaration. This decorator can be used to define a +class that is immutable immediately after its definition has been +evaluated. + +When used on a class, the decorators propagate to any directly nested +declaration. For example, + +.. code-block:: python + + @freezable + class Foo: + def frob(self, a, b, c): + class Bar: + pass + class Baz: + def quux(self, a, b, c): + pass + +is equivalent to + +.. code-block:: python + + @freezable + class Foo: + @freezable # from Foo + def frob(self, a, b, c): + class Bar: + pass + @freezable # from Foo + class Baz: + @freezable # from Foo via Baz + def quux(self, a, b, c): + pass + +The reason why the decoration does not propagate to ``Bar`` is because +of technical limitations and a desire to keep complexity down. Any +arguments to a decorator are propagated along with the decorator. + +Propagation can cause a declaration to become multiply decorated when an +outer decorator is propagated to a nested declaration. The list below +explains what happens in this case. The leftmost is the outer decorator +and the rightmost the inner. + +- ``@immutable`` + ``@immutable`` = ``@immutable`` +- ``@immutable`` + ``@freezable`` = ``@immutable`` +- ``@immutable`` + ``@unfreezable`` = raises exception +- ``@freazable`` + ``@immutable`` = ``@immutable`` +- ``@freazable`` + ``@freezable`` = ``@freezable`` +- ``@freazable`` + ``@unfreezable`` = ``@unfreezable`` +- ``@unfreezable`` + ``@immutable`` = ``@immutable`` +- ``@unfreezable`` + ``@freezable`` = ``@freezable`` +- ``@unfreezable`` + ``@unfreezable`` = ``@unfreezable`` + +For clarity, the first line means that two ``@immutable`` decorators is +equivalent to a single ``@immutable`` decorator. Note that nesting +something ``@unfreezable`` inside something that is ``@immutable`` raises +an exception since this is not meaningful (the ``@unfreezable`` thing +will not be reachable in the program so this is most likely an error). + +Arguments are always joined together, so if ``@immutable("a", "b")`` is +nested inside ``@freezable("b", "c")``, the result is +``@immutable("a", "b", "c")``. + +Decorator arguments – white listing to enable freeze propagation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Without explicit annotations, declarations can become immutable if the module +that declares them sets a ``__freezable__`` field to 1. Freezing such +functions will fail if they capture mutable state. + +.. code-block:: python + + __freezable__ = 1 + + x = [47] + y = [11] + def foo(a): + x.append(a) + y.pop() + freeze(foo) # fails + +With an ``@freezable`` annotation, freezing the function succeeds if the +mutable state it captures is found in the variables mentioned as +arguments to the decorator, and that state can be successfully made immutable. + +.. code-block:: python + + x = [47] + y = [11] + @freezable("x", "y") + def foo(a): + x.append(a) + y.pop() + freeze(foo) # succeeds + +The behaviour is the same, regardless of whether the variables captured +are from globals or an enclosing frame. + +.. code-block:: python + + def outer(): + x = [47] + y = [11] + @freezable("x", "y") + def foo(a): + x.append(a) + y.pop() + return foo + + foo = outer() + freeze(foo) # succeeds + +Explicitly naming what may become immutable as a side-effect of freezing a +function (or type) can serve as documentation and could be useful input +to a linter. + +Note that the white listing in arguments to ``@freezable`` looks at the +*contents* of variables (at the time of freezing) so the following works +as ``x`` and ``y`` alias. + +.. code-block:: python + + x = [47] + y = x + @freezable("x") + def foo(a): + x.append(a) + y.pop() + freeze(foo) # succeeds + +Also note that we only care about freezing mutable state. If we capture +a variable outside of the list of permitted variables, but that variable +contains an immutable object, freezing will not fail. Thus, the second +call to ``freeze`` below will succeed. + +.. code-block:: python + + x = [47] + z = [11] + y = z + @freezable("x") + def foo(a): + x.append(a) + y.pop() + freeze(z) # freeze the list object referenced by y and z + freeze(foo) # succeeds + +To permit a freezable function to freeze anything that it captures: +``@freezable("*")``. + +Detecting freezing outside of the permitted set +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The decorator is an effect annotation, similar to a ``throws`` +declaration in Java. Now we discuss the meaning of capturing variables +(referencing mutable objects) which were not explicitly listed as OK to +freeze. + +**Strict:** throw an exception. If a function evolves so that freezing +it propagates outside of the permitted set, this is a design error that +should be fixed. + +**Relaxed:** replace any captured value outside of the permitted set by +an immutable dummy value. This permits the function to be made immutable, but +protects all values we hadn’t explicitly permitted to become immutable. +This may cause the function to become incapacitated, but +it also enables writing functions that behave differently depending on +whether they are immutable or not: + +.. code-block:: python + + x = [47] + y = [11] + @freezable("x") + def foo(a): + x.append(a) + if not is_immutable(foo): + y.pop() + +Freezing ``foo`` above will not cause ``y`` to become immutable, and the +function is implemented in such a way that it does not try to mutate +``y`` if it is immutable. Note that it is not possible to analyse functions +to see if they might access the dummy value if they are immutable. These +kinds of errors will always be caught dynamically. + +For ``@immutable``, only the strict semantics is meaningful. For +``@freezable``, there are pros and cons with both. + +**TODO** make a decision before posting this PEP – maybe just use strict +to keep complexity down? + +Shared field (stage 2) +---------------------- + +Shared fields permit multiple interpreters to share a mutable field, +which may only hold immutable objects. It was described in the escape +hatch section above. + +The code below is not how shared fields are implemented, but describes +the behaviour of a shared field, except that freezing the field object +does not prevent subsequent assignment to ``self.value``. (To be clear: +this cannot be implemented in pure Python since it is not safe for +freezing to exclude ``self.value``.) + +.. code-block:: python + :caption: **Listing 26:** Semantics of shared fields described through Python + + import threading + import immutable + + def shared(initial_value=None): + @immutable + class SharedField: + def __init__(self, initial_value): + # Note, this field stays mutable when freezing + self.value = initial_value + self.lock = threading.Lock() + + def set(self, new_value): + if not is_immutable(new_value): + raise RuntimeError("Shared fields only store immutable values") + with self.lock: + old_value = self.value + self.value = new_value + return old_value + + def get(self): + with self.lock: + old_value = self.value + return old_value + + def swap(self, expected_value, new_value): + if not is_immutable(new_value): + raise RuntimeError("Shared fields only store immutable values") + with self.lock: + old_value = self.value + if old_value != expected_value: + return old_value + else: + self.value = new + return expected_value + + return immutable.freeze(SharedField(initial_value)) + +Local fields (stage 2) +---------------------- + +Local fields permits an object to have a field that holds different +(mutable or immutable) values for different interpreters, i.e the field +is “interpreter-local”, analogous to how ``threading.local()`` works. It +was described in the escape hatch section above. + +The code below is not how interpreter-local fields are implemented, but +describes the behaviour of such fields, except that freezing the field +object does not prevent subsequent updates to the ``interpreter_map``. +(To be clear: this cannot be implemented in pure Python since it is not +safe for freezing to exclude ``interpreter_map``.) + +.. code-block:: python + :caption: **Listing 27:** Semantics of local fields described through Python + + import immutable + + def local(init_func=None): + interpreter_map = {} + + @immutable("interpreter_map") # abuse of notation, interpreter map is not made immutable + class LocalField: + def _resolve(self): + import sys + current = sys.interpreter_id + try: + return interpreter_map[current] + except KeyError: + value = init_func() + interpreter_map[current] = value + return value + + def __getattr__(self, name): + target = self._resolve() + if name == "get": + # used to read the value of the field, not dereference it + return target + else: + return getattr(target, name) + + def __setattr__(self, name, value): + if name == "set": + # used to set the value of the field, not update fields in the existing value + import sys + current = sys.interpreter_id + interpreter_map[current] = value + else: + target = self._resolve() + setattr(target, name, value) + + def __delattr__(self, name): + target = self._resolve() + delattr(target, name) + + def __call__(self, *args, **kwargs): + target = self._resolve() + return target(*args, **kwargs) + + def __repr__(self): + target = self._resolve().__repr__() + + return immutable.freeze(LocalField()) + +Implementation +============== + +We will use two bits as flags per Python object: the first will be used +to track immutability; the second will be used by the SCC algorithm. +This will be done without extending the size of the Python object +header. + +Immutability is enforced through run-time checking. The macro +``Py_CHECKWRITE(op)`` is inserted on all paths that are guaranteed to +end up in a write to ``op``. The macro inspects the immutability flag in +the header of ``op`` and signals an error if the immutability flag is +set. + +A typical use of this check looks like this: + +.. code-block:: c + :caption: **Listing 28:** Example of call to ``Py_CHECKWRITE``. + + if (!Py_CHECKWRITE(op)) { // perform the check + PyErr_WriteToImmutable(op); // raise the error if the check fails + return NULL; // abort the write + } + ... // code that performs the write + +Writes are common in the CPython code base and the writes lack a common +“code path” that they pass. To this end, the PEP requires a +``Py_CHECKWRITE`` call to be inserted and there are several places in +the CPython code base that are changed as a consequence of this PEP. So +far we have identified around 70 places in core Python which needed a +``Py_CHECKWRITE`` check. Modules in the standard library have required +somewhere between 5 and 15 checks per module. + +While the ``freeze(obj)`` function is available to Python programmers in +the immutable module, the actual freezing code has to live inside core +Python. This is for three reasons: + +- The core object type needs to be able to freeze just-in-time + dictionaries created by its accessors when the object itself is + immutable. +- The managed buffer type needs to be immutable when the object it is + created from is immutable. +- Teardown of strongly connected components of immutable objects + (discussed further down in this section) must be hooked into + ``Py_DECREF``. + +As such, we implement a function which is not in the limited API (and +thus not part of the stable C ABI) called ``_PyImmutability_Freeze`` +which performs the freezing logic. This is used internally as a C Python +implementation detail, and then exposed to Python through the +``freeze(obj)`` function in the immutable module. + +Atomic reference counting +------------------------- + +Note: This section does not apply to free-threaded Python. + +As a necessary requirement for directly sharing objects across +sub-interpreters, reference counts for immutable objects must be managed +with atomic operations. This is handled in the reference counting macro +by branching on the immutability flag, and using atomic operations only +if the bit it set. + +Management of immutable objects +------------------------------- + +Note: This section does not apply to free-threaded Python. + +When objects are made immutable, we remove them from the heap of their +creating interpreter. This is done by unlinking them from the GC work +list that all objects participate in. If the object ever becomes +garbage, it will be added back to its creating interpreter, which will +handle cleanup and finalization. + +Dealing with cycles in immutable object graphs +---------------------------------------------- + +In `previous work `__, +we have identified that objects that make up cyclic immutable garbage +will always have the same lifetime. This means that a single reference +count could be used to track the lifetimes of all the objects in such a +strongly connected component (SCC). + +As part of freezing, we perform an SCC analysis that creates a +designated (atomic) reference count for every SCC created as part of +freezing the object graph. Reference count manipulations on any object +in the SCC is “forwarded” to that shared reference count. This can be +done without bloating objects by repurposing the existing reference +counter data to be used as a pointer to the shared counter. + +This technique permits handling cyclic garbage using plain reference +counting, and because of the single reference count for an entire SCC, +we will detect when all the objects in the SCC expire at once. + +Weak references +--------------- + +Weak references are turned into strong references during freezing. This +is so that an immutable object cannot be effectively mutated by a weakly +referenced nested object being garbage collected. If a weak reference +loses its object during freezing, we treat this as a failure to freeze +since the program is effectively racing with the garbage collector. + +New Obligations on C Extensions +------------------------------- + +**TODO** @MattJ -- is the below still correct? + +As immutability support must be opted in, there are no *obligations* for +C extensions that do not want to add support for immutability. + +Because our implementation builds on information available to the +CPython cycle detector, types defined through C code will support +immutability “out of the box” as long as they use Python standard types +to store data and uses the built-in functions of these types to modify +the data. + +To make its instances freezable, a type that uses C extensions that adds +new functionality implemented in C must register themselves using +``register_freezable(type)``. Example: + +.. code-block:: python + :caption: **Listing 29:** + + PyObject *register_freezable = _PyImport_GetModuleAttrString("immutable", "register_freezable"); + if(register_freezable != NULL) + { + PyObject* result = PyObject_CallOneArg(register_freezable, (PyObject *)st->Element_Type); + if(result == NULL){ + goto error; + } + Py_DECREF(register_freezable); + } + +If you construct a C type using freezable metaclasses it will itself be +freezable, without need for explicit registration. + +To properly support immutability, C extensions that directly write to +data which can be made immutable should add the ``Py_CHECKWRITE`` macro +shown above on all paths in the code that lead to writes to that data. +Notably, if C extensions manage their data through Python objects, no +changes are needed. + +C extensions that define data that is outside of the heap traced by the +CPython cycle detector should either manually implement freezing by +using ``Py_CHECKWRITE`` or ensure that all accesses to this data is +*thread-safe* and that it does not cause a mutable object from one +sub-interpreter to become accessible to another sub-interpreter. + +Changes to the C ABI +-------------------- + +- ``Py_CHECKWRITE`` +- ``_Py_IsImmutable`` +- ``PyErr_WriteToImmutable`` + +Changes to the internal API +--------------------------- + +- ``_PyType_HasExtensionSlots(PyTypeObject*)`` – determines whether a + type object adds novel functionality in C +- ``_PyNotFreezable_Type`` +- ``_PyImmutability_Freeze`` +- ``_RegisterFreezable`` +- ``_PyImmutability_IsFreezable`` + +Mapping changes to stages +------------------------- + +**TODO** @MattJ -- please check if this seems right + +Stage 1 +~~~~~~~ + +- is_immutable +- the immutable types shared across interpreters +- sharing immutable objects across interpreters +- atomic RC for immutable objects +- remove immutable objects from sub-interpreter heap (and put back) +- disabled +- make certain types and objects immutable + +Stage 2 +~~~~~~~ + +- scc +- freeze function +- @immutable +- shared and local fields +- make certain types and objects immutable + +Stage 3 +~~~~~~~ + +- NotFreezable +- make_module_shared +- import_as_shared +- @freezable and @unfreezable +- make certain types and objects immutable +- sharing of immutable module objects + +Future extensions and considerations +==================================== + +Notes on hashing +---------------- + +Deep immutability opens up the possibility of any freezable object being +hashable, due to the fixed state of the object graph making it possible +to compute stable hash values over the graph as is the case with tuple +and frozenset . However, there are several complications (listed below) +which should be kept in mind for any future PEPs which build on this +work at add hashability for immutable objects: + +Instance versus type hashability +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +At the moment, the test for hashability is based upon the presence (or +absence) of a ``__hash__`` method and an ``__eq__`` method. Places where +``PyObject_HashNotImplemented`` is currently used would need to be +modified as appropriate to have a contextual logic which provides a +default implementation that uses ``id()`` if the object instance is +immutable, and throws a type error if not. + +This causes issues with type checks, however. The check of +``isinstance(x, Hashable)`` would need to become contextual, and +``issubclass(type(x), Hashable)`` would become underdetermined for many +types. Handling this in a way that is not surprising will require +careful design considerations. + +Equality of immutable objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One consideration with the naive approach (i.e., hash via id()) is that +it can result in confusing outcomes. For example, if there were to be +two lists: + +.. code-block:: python + + a = [1, 2, 3, 4] + b = [1, 2, 3, 4] + assert(hash(a) == hash(b)) + +There would be a reasonable expectation that this assertion would be +true, as it is for two identically defined tuples. However, without a +careful implementation of ``__hash__`` and ``__eq__`` this would not be +the case. Our opinion is that an approach like that used in tuplehash is +recommended in order to avoid this behavior. + +Types +----- + +Support for immutability in the type system is worth exploring in the +future. + +Currently in Python, ``x: Foo`` does not give very strong guarantees +about whether ``x.bar(42)`` will work or not, because of Python’s strong +reflection support that permits changing a class at run-time, or even +changing the type of an object. Making objects immutable in-place +exacerbates this situation as ``x.bar(42)`` may now fail because ``x`` +has been made immutable. However, in contrast to failures due to +reflective changes of a class, a ``NotFreezableError`` will point to the +place in the code where the object was made immutable. This should facilitate +debugging. + +In short: the possibility of making objects immutable in-place does not +weaken type-based reasoning in Python on a fundamental level. However, +if immutability becomes very frequently used, it may lead to the +unsoundness which already exists in Python’s current typing story +surfacing more frequently. + +There are several challenges when adding immutability to a type system +for an object-oriented programming language. First, self typing becomes +more important as some methods require that self is mutable, some +require that self is immutable (e.g. to be thread-safe), and some +methods can operate on either self type. The latter subtly needs to +preserve the invariants of immutability but also cannot rely on +immutability. We would need a way of expressing this in the type system. +This could probably be done by annotating the self type in the three +different ways above – mutable, immutable, and works either way. + +A possibility would be to express the immutable version of a type ``T`` +as the intersection type ``immutable & T`` and a type that must preserve +immutability but may not rely on it as the union of the immutable +intersection type with its mutable type ``(immutable & T) | T``. + +Furthermore, deep immutability requires some form of “view-point +adaption”, which means that when ``x`` is immutable, ``x.f`` is also +immutable, regardless of the declared type of ``f``. View-point +adaptation is crucial for ensuring that immutable objects treat +themselves correctly internally and is not part of standard type systems +(but well-researched in academia). + +Making freeze a soft keyword as opposed to a function has been proposed +to facilitate flow typing. We believe this is an excellent proposal to +consider for the future in conjunction with work on typing immutability. + +Data-race free Python +--------------------- + +This PEP adds support for immutable objects to Python and importantly +permits sub-interpreters to directly share *immutable* objects. As a +future PEP will we propose an extension that also permits directly +sharing *mutable* objects. We refer to this proposal as “data-race free +Python” or “DRF Python” for short. In that future proposal, mutable +objects will only be accessible to one sub-interpreter at a time, but +can be passed around and shared by reference. We believe that making +Python data-race free is the right programming model for the langauge, +and aim to be compatible with both sub-interpreters and free-threaded +Python. + +DRF Python will borrow concepts from ownership (namely region-based +ownership, see e.g. `Cyclone `__) to +make Python programs data-race free by construction. A description of +the ownership model that we envision can be found in our PLDI 2025: +`Dynamic Region Ownership for Concurrency +Safety `__. + +It is important to point out that data-race free Python is different +from free-threaded Python, but aims to be fully compatible with it, and +we believe that they can benefit from each other. In essence +free-threaded Python focuses on making the CPython run-time resilient +against data races in Python programs: a poorly synchronized Python +program should not be able to corrupt reference counts, or other parts +of the Python interpreter. The complementary goal pursued by DRF Python +is to make it impossible for Python programs to have data races. Support +for deeply immutable data can be seen as the first step towards this +goal. + +Reference implementation +======================== + +**TODO** @MattJ? Write up the relationship between the above and what is +in our prototype. + +TODOs +===== + +- Do we cover C extensions enough? +- Do we need a separate discussion about backwards compatibility? +- We currently do not discuss builtins +- We should discuss locks being morally immutable diff --git a/peps/pep-0795/diagram_1.mmd b/peps/pep-0795/diagram_1.mmd new file mode 100644 index 00000000000..c5bea541714 --- /dev/null +++ b/peps/pep-0795/diagram_1.mmd @@ -0,0 +1,24 @@ + + graph LR + subgraph Sub 1 + A[A] + D[D] + end + + subgraph Sub 2 + B[B] + end + + C:::imm + + A ----> C + B ----> C + C ----> D + A -. GIL 1 .-> C + B -. GIL 2 .-> C + C -. GIL 1 .-> D + C -. GIL 2 .-> D + + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + linkStyle 4,6 stroke:#f00,stroke-width:1px,color:blue; + linkStyle 3,5 stroke:#90f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_1.svg b/peps/pep-0795/diagram_1.svg new file mode 100644 index 00000000000..4fb651a8fb8 --- /dev/null +++ b/peps/pep-0795/diagram_1.svg @@ -0,0 +1 @@ +

    Sub 2

    Sub 1

    GIL 1

    GIL 2

    GIL 1

    GIL 2

    A

    D

    B

    C

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_10.mmd b/peps/pep-0795/diagram_10.mmd new file mode 100644 index 00000000000..ee3ffb0b303 --- /dev/null +++ b/peps/pep-0795/diagram_10.mmd @@ -0,0 +1,29 @@ + + graph LR + subgraph Sub 1 + A[A] + end + + subgraph Sub 2 + B[B] + end + + C[Cell]:::imm + D[Shared field]:::fake_imm + E[2]:::imm + + A ----> C + B ----> C + C ----> D + D ----> E + A -. GIL 1 .-> C + C -. GIL 1 .-> D + D -. GIL 1 .-> E + B -. GIL 2 .-> C + C -. GIL 2 .-> D + D -. GIL 2 .-> E + + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + classDef fake_imm fill:#aaa,stroke:#000,stroke-width:1px; + linkStyle 4,5,6 stroke:#f00,stroke-width:1px,color:blue; + linkStyle 7,8,9 stroke:#90f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_10.svg b/peps/pep-0795/diagram_10.svg new file mode 100644 index 00000000000..2588a1164ba --- /dev/null +++ b/peps/pep-0795/diagram_10.svg @@ -0,0 +1 @@ +

    Sub 2

    Sub 1

    GIL 1

    GIL 1

    GIL 1

    GIL 2

    GIL 2

    GIL 2

    A

    B

    Cell

    Shared field

    2

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_11.mmd b/peps/pep-0795/diagram_11.mmd new file mode 100644 index 00000000000..b5ff5d003dc --- /dev/null +++ b/peps/pep-0795/diagram_11.mmd @@ -0,0 +1,33 @@ + + graph LR + subgraph Sub 1 + A[A] + D1[interpreter-local storage] + E[E] + end + + subgraph Sub 2 + B[B] + D2[interpreter-local storage] + F[F] + end + + C[Prime factoriser]:::imm + + A ----> C + B ----> C + C ----> D1 + C ----> D2 + D1 ----> E + D2 ----> F + A -. GIL 1 .-> C + C -. GIL 1 .-> D1 + D1 -. GIL 1 .-> E + B -. GIL 2 .-> C + C -. GIL 2 .-> D2 + D2 -. GIL 2 .-> F + + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + classDef fake_imm fill:#aaa,stroke:#000,stroke-width:1px; + linkStyle 6,7,8 stroke:#f00,stroke-width:1px,color:blue; + linkStyle 9,10,11 stroke:#90f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_11.svg b/peps/pep-0795/diagram_11.svg new file mode 100644 index 00000000000..7f2e80f50a8 --- /dev/null +++ b/peps/pep-0795/diagram_11.svg @@ -0,0 +1 @@ +

    Sub 2

    Sub 1

    GIL 1

    GIL 1

    GIL 1

    GIL 2

    GIL 2

    GIL 2

    A

    interpreter-local storage

    E

    B

    interpreter-local storage

    F

    Prime factoriser

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_12.mmd b/peps/pep-0795/diagram_12.mmd new file mode 100644 index 00000000000..e3ce712f695 --- /dev/null +++ b/peps/pep-0795/diagram_12.mmd @@ -0,0 +1,50 @@ + + graph + subgraph Module1 + A[Type1] + B[Func1] + X[Var1] + subgraph Module2 + C[Type2] + D[Func2] + Y[Var2] + end + end + + subgraph Module3 + E[Type3] + EE[Type4] + Z[Var3] + F[Func3] + end + + subgraph Program + O1 + O2 + x + y + m3 + m1 + end + + A -- calls --> B + B -- uses --> C + B -- imports --> Module2 + B -- reads --> X + B -- writes --> X + C -- calls --> D + C -- writes --> Y + + E -- reads --> Z + F -- writes --> Z + + F -- imports --> Module2 + + EE -- extends --> E + + O1 -- \_\_class__ --> EE + O2 -- \_\_class__ --> A + x --> O1 + y --> O2 + m1 -- imports --> Module1 + m3 -- imports --> Module3 diff --git a/peps/pep-0795/diagram_12.svg b/peps/pep-0795/diagram_12.svg new file mode 100644 index 00000000000..81a4348f763 --- /dev/null +++ b/peps/pep-0795/diagram_12.svg @@ -0,0 +1 @@ +

    Program

    Module3

    Module1

    Module2

    calls

    uses

    reads

    writes

    calls

    writes

    reads

    writes

    extends

    __class__

    __class__

    imports

    imports

    imports

    imports

    Type1

    Func1

    Var1

    Type2

    Func2

    Var2

    Type3

    Type4

    Var3

    Func3

    O1

    O2

    x

    y

    m3

    m1

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_2.mmd b/peps/pep-0795/diagram_2.mmd new file mode 100644 index 00000000000..d0359dbc3bc --- /dev/null +++ b/peps/pep-0795/diagram_2.mmd @@ -0,0 +1,18 @@ + + graph LR + subgraph Sub 1 + A[A] + end + + subgraph Sub 2 + B[B] + end + + C:::imm + D:::imm + + A ----> C + B ----> C + C -- \_\_class__ --> D + + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; diff --git a/peps/pep-0795/diagram_2.svg b/peps/pep-0795/diagram_2.svg new file mode 100644 index 00000000000..3c089b66d0b --- /dev/null +++ b/peps/pep-0795/diagram_2.svg @@ -0,0 +1 @@ +

    Sub 2

    Sub 1

    __class__

    A

    B

    C

    D

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_3.mmd b/peps/pep-0795/diagram_3.mmd new file mode 100644 index 00000000000..5ecdc912904 --- /dev/null +++ b/peps/pep-0795/diagram_3.mmd @@ -0,0 +1,8 @@ + + graph LR; + O[Stack frame]-- x -->A + A-- f -->B + A-- g -->B + B-- h -->A + B-- j -->C + O-- y -->C diff --git a/peps/pep-0795/diagram_3.svg b/peps/pep-0795/diagram_3.svg new file mode 100644 index 00000000000..67031fc103c --- /dev/null +++ b/peps/pep-0795/diagram_3.svg @@ -0,0 +1 @@ +

    x

    f

    g

    h

    j

    y

    Stack frame

    A

    B

    C

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_4.mmd b/peps/pep-0795/diagram_4.mmd new file mode 100644 index 00000000000..492ed9294e1 --- /dev/null +++ b/peps/pep-0795/diagram_4.mmd @@ -0,0 +1,14 @@ + + graph TD; + A[Stack frame]-- d -->B[DieInstance] + B-- sides -->12:::imm + B-- \_\_class__ -->C[Die]:::imm + C-- \_\_class__ -->D[type]:::imm + C-- \_\_bases__-->T[tuple]:::imm + T--> E[object]:::imm + E-- \_\_class__ -->F[type]:::imm + C-- \_\_init__ -->G[Function object]:::imm + C-- set_sides -->H[Function object]:::imm + C-- roll -->I[Function object]:::imm + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + linkStyle 3,4,5,6,7,8,9 stroke:#00f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_4.svg b/peps/pep-0795/diagram_4.svg new file mode 100644 index 00000000000..1e5050cced4 --- /dev/null +++ b/peps/pep-0795/diagram_4.svg @@ -0,0 +1 @@ +

    d

    sides

    __class__

    __class__

    __bases__

    __class__

    __init__

    set_sides

    roll

    12

    Stack frame

    DieInstance

    Die

    type

    tuple

    object

    type

    Function object

    Function object

    Function object

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_5.mmd b/peps/pep-0795/diagram_5.mmd new file mode 100644 index 00000000000..bdfd444bd3f --- /dev/null +++ b/peps/pep-0795/diagram_5.mmd @@ -0,0 +1,14 @@ + + graph TD; + A[Stack frame]-- d -->B[DieInstance]:::imm + B-- sides -->12:::imm + B-- \_\_class__ -->C[Die]:::imm + C-- \_\_class__ -->D[type]:::imm + C-- \_\_bases__-->T[tuple]:::imm + T--> E[object]:::imm + E-- \_\_class__ -->F[type]:::imm + C-- \_\_init__ -->G[Function object]:::imm + C-- set_sides -->H[Function object]:::imm + C-- roll -->I[Function object]:::imm + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + linkStyle 1,2,3,4,5,6,7,8,9 stroke:#00f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_5.svg b/peps/pep-0795/diagram_5.svg new file mode 100644 index 00000000000..d5e536ae77e --- /dev/null +++ b/peps/pep-0795/diagram_5.svg @@ -0,0 +1 @@ +

    d

    sides

    __class__

    __class__

    __bases__

    __class__

    __init__

    set_sides

    roll

    12

    Stack frame

    DieInstance

    Die

    type

    tuple

    object

    type

    Function object

    Function object

    Function object

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_6.mmd b/peps/pep-0795/diagram_6.mmd new file mode 100644 index 00000000000..1426f72b64a --- /dev/null +++ b/peps/pep-0795/diagram_6.mmd @@ -0,0 +1,9 @@ + + graph TD; + A[Stack frame]-- f1 -->B[FractionInstance1] + B-- n -->1:::imm + B-- d -->3:::imm + A-- f2 -->D[FractionInstance2] + D-- n -->2:::imm + D-- d -->7:::imm + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; diff --git a/peps/pep-0795/diagram_6.svg b/peps/pep-0795/diagram_6.svg new file mode 100644 index 00000000000..351417d0556 --- /dev/null +++ b/peps/pep-0795/diagram_6.svg @@ -0,0 +1 @@ +

    f1

    n

    d

    f2

    n

    d

    1

    2

    3

    7

    Stack frame

    FractionInstance1

    FractionInstance2

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_7.mmd b/peps/pep-0795/diagram_7.mmd new file mode 100644 index 00000000000..68c9360924e --- /dev/null +++ b/peps/pep-0795/diagram_7.mmd @@ -0,0 +1,10 @@ + + graph TD; + A[Stack frame]-- f1 -->B[FractionInstance1]:::imm + B-- n -->1:::imm + B-- d -->3:::imm + A-- f2 -->D[FractionInstance2] + D-- n -->2:::imm + D-- d -->7:::imm + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + linkStyle 1,2 stroke:#00f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_7.svg b/peps/pep-0795/diagram_7.svg new file mode 100644 index 00000000000..0a821a28209 --- /dev/null +++ b/peps/pep-0795/diagram_7.svg @@ -0,0 +1 @@ +

    f1

    n

    d

    f2

    n

    d

    1

    2

    3

    7

    Stack frame

    FractionInstance1

    FractionInstance2

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_8.mmd b/peps/pep-0795/diagram_8.mmd new file mode 100644 index 00000000000..32530e4d365 --- /dev/null +++ b/peps/pep-0795/diagram_8.mmd @@ -0,0 +1,28 @@ + + graph TD; + A[Stack frame]-- f1 -->B[Fraction instance 1] + B-- n -->1:::imm + B-- d -->3:::imm + A-- f2 -->D[Fraction instance 2] + D-- n -->2:::imm + D-- d -->7:::imm + B-- \_\_class__ -->E[Fraction] + D-- \_\_class__ -->E + 1-- \_\_class__ -->int:::imm + 3-- \_\_class__ -->int + 2-- \_\_class__ -->int + 7-- \_\_class__ -->int + int -- \_\_class__ -->type:::imm + E-- \_\_init__ -->AA[Function 3] + E-- \_\_add__ -->BB[Function 4] + E-- \_\_repr__ -->CC[Function 5] + E-- \_\_class__ -->type:::imm + A-- gcd -->DD[Function 1] + A-- print_fraction -->EE[Function 2] + AA-- gcd -->DD + BB-- Fraction -->E + int -- superclass -->O[object]:::imm + E -- superclass -->O + O -- \_\_class__ -->type:::imm + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + linkStyle 8,9,10,11,12,21,23 stroke:#00f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_8.svg b/peps/pep-0795/diagram_8.svg new file mode 100644 index 00000000000..6c5f1d0d015 --- /dev/null +++ b/peps/pep-0795/diagram_8.svg @@ -0,0 +1 @@ +

    f1

    n

    d

    f2

    n

    d

    __class__

    __class__

    __class__

    __class__

    __class__

    __class__

    __class__

    __init__

    __add__

    __repr__

    __class__

    gcd

    print_fraction

    gcd

    Fraction

    superclass

    superclass

    __class__

    1

    2

    3

    7

    Stack frame

    Fraction instance 1

    Fraction instance 2

    Fraction

    int

    type

    Function 3

    Function 4

    Function 5

    Function 1

    Function 2

    object

    \ No newline at end of file diff --git a/peps/pep-0795/diagram_9.mmd b/peps/pep-0795/diagram_9.mmd new file mode 100644 index 00000000000..6605f6b5400 --- /dev/null +++ b/peps/pep-0795/diagram_9.mmd @@ -0,0 +1,41 @@ + + graph TD; + A[Stack frame]-- f1 -->B[Fraction instance 1] + B-- n -->1 + B-- d -->3 + A-- f2 -->D[Fraction instance 2] + D-- n -->2 + D-- d -->7 + B-- \_\_class__ -->E[Fraction] + D-- \_\_class__ -->E + 1-- \_\_class__ -->int + 3-- \_\_class__ -->int + 2-- \_\_class__ -->int + 7-- \_\_class__ -->int + int -- \_\_class__ -->type + E-- \_\_init__ -->AA[Function 3] + E-- \_\_add__ -->BB[Function 4] + E-- \_\_repr__ -->CC[Function 5] + E-- \_\_class__ -->type + A-- gcd -->DD[Function 1] + A-- print_fraction -->EE[Function 2] + AA-- gcd -->DD + BB-- Fraction -->E + int -- superclass -->O[object]:::imm + E -- superclass -->O + O -- \_\_class__ -->type + + B:::imm + 1:::imm + 3:::imm + 2:::imm + 7:::imm + int:::imm + type:::imm + E:::imm + AA:::imm + BB:::imm + CC:::imm + DD:::imm + classDef imm fill:#ADD8E6,stroke:#003366,stroke-width:1px,color:#003366; + linkStyle 1,2,6,8,9,10,11,12,13,14,15,16,19,20,21,22,23 stroke:#00f,stroke-width:1px,color:blue; diff --git a/peps/pep-0795/diagram_9.svg b/peps/pep-0795/diagram_9.svg new file mode 100644 index 00000000000..c8485ba5504 --- /dev/null +++ b/peps/pep-0795/diagram_9.svg @@ -0,0 +1 @@ +

    f1

    n

    d

    f2

    n

    d

    __class__

    __class__

    __class__

    __class__

    __class__

    __class__

    __class__

    __init__

    __add__

    __repr__

    __class__

    gcd

    print_fraction

    gcd

    Fraction

    superclass

    superclass

    __class__

    1

    2

    3

    7

    Stack frame

    Fraction instance 1

    Fraction instance 2

    Fraction

    int

    type

    Function 3

    Function 4

    Function 5

    Function 1

    Function 2

    object

    \ No newline at end of file