Skip to content

Commit 2fc4375

Browse files
Pep795 comments 1 (#16)
* Added subclass info; clarified explicit objects * Bug fixes in the RST
1 parent e069316 commit 2fc4375

File tree

1 file changed

+52
-21
lines changed

1 file changed

+52
-21
lines changed

peps/pep-0795.rst

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ whereas ``freeze(o, o.__class__)`` freezes both ``o`` and its class
404404
explicitly, and at the same time).
405405

406406
.. code-block:: python
407-
:caption: **Listing 2.a:** By default, types must be frozen explicitly.
407+
:caption: **Listing 2.a:** By default, types must be frozen explicitly or freezing fails.
408408
409409
class Foo:
410410
pass
@@ -434,7 +434,7 @@ a module called ``immutable``. The listing below revisits the listing
434434
above and uses the ``@frozen`` decorator on ``Foo``.
435435

436436
.. code-block:: python
437-
:caption: **Listing 2.b:** By default, types must be frozen explicitly.
437+
:caption: **Listing 2.b:** By default, types must be frozen explicitly or else fail.
438438
439439
from immutable import freeze, is_frozen, frozen
440440
@@ -475,7 +475,9 @@ An attempt at mutating ``C`` through ``y`` will result in
475475
Freeze propagation is similar to how static annotations such
476476
as ``const`` from C or C++ propagate through a code base, except
477477
at run-time instead of compile-time. This PEP limits or manages freeze
478-
propagation by making user-defined types explicitly freezable,
478+
propagation by only permitting user-defined types to be frozen if they
479+
are frozen *explicitly* (meaning the user passes a direct reference
480+
to the type as an argument to ``freeze()`` or uses a decorator on it)
479481
providing a way to hook into the freeze mechanism, and by
480482
allowing opting out of freezing altogether or for some limited
481483
duration.
@@ -661,7 +663,7 @@ supported since the value is immutable.
661663
662664
# freeze(d) -- will fail unless Die is @frozen or @freezable
663665
664-
freeze(Die)
666+
freeze(Die) # After this d can be frozen
665667
is_frozen(Die) # True
666668
is_frozen(Die.roll) # True
667669
@@ -707,16 +709,16 @@ Note that freezing is *in-place*; ``freeze(obj)`` freezes ``obj``, not a copy.
707709

708710
.. _freezable:
709711

710-
Freezability - Unfreezable and explicitly freezable objects
711-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
712+
Freezability - Unfreezable objects and objects which must be explicitly frozen
713+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
712714

713715
The immutable module provides the function ``set_freezable(obj, status=Yes)``
714716
which controls if and how an object is freezable. Most
715717
objects are freezable by default, meaning that freezing can propagate
716-
to them. However, functions and types are explicitly freezable by
717-
default (``set_freezable(obj, Explicit)``) meaning that freezing
718-
will never propagate to them and they can only be frozen when they
719-
are explicitly passed in to ``freeze()``. Objects can also be marked as
718+
to them. However, types cannot be frozen through propagation by
719+
default -- they can only be frozen when they
720+
are explicitly passed in to ``freeze()`` (``set_freezable(obj, Explicit)``).
721+
Objects can also be marked as
720722
unfreezable (``set_freezable(obj, No)``) which will result in an error
721723
when someone attempts to freeze the object. The values for ``Yes``,
722724
``No`` and ``Explicit`` are defined in the immutable module.
@@ -899,6 +901,34 @@ itself during initialisation.
899901
current_module = sys.modules[__name__]
900902
set_freezable(current_module, immutable.Proxy)
901903
904+
905+
Accessing subclass information and subclassing immutable classes
906+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
907+
908+
When a class object becomes immutable, its base classes
909+
replace their interpreter-local registry of mutable
910+
subclasses with an internal, shared list of weak references
911+
to immutable subclasses. All mutable subclasses remain
912+
recorded in interpreter-local registries (also using
913+
weak references). Any subsequent subclassing of the base
914+
in a given interpreter adds the new subclass to that
915+
interpreter's local registry.
916+
917+
Let ``A`` be an immutable class and ``B`` an immutable subclass of
918+
``A``. When ``B`` is made immutable, its weak reference is moved
919+
from the interpreter-local registry into ``A``'s shared list of
920+
immutable subclasses.
921+
922+
Calls to ``type.__subclasses__()`` in any interpreter return
923+
a fresh list containing all live immutable subclasses plus
924+
the interpreter's own mutable subclasses. Publication of
925+
immutable subclasses across interpreters is eventually
926+
consistent.
927+
928+
Note that once a class is immutable, reassignment of
929+
``__bases__`` is prohibited.
930+
931+
902932
.. _summary-2:
903933

904934
Summary
@@ -1164,14 +1194,15 @@ wants to limit immutability to something that happens only
11641194
at creation. This is not compatible with Python patterns like
11651195
monkey patching and cyclic structures. (Or how types are defined.)
11661196

1167-
By making classes *explicitly freezable* we avoid freezing one
1197+
By making classes require an explicit call to freeze we avoid freezing one
11681198
object propagating to all objects of the same type at the same
11691199
time as we stop careless freezing of objects. To make a class
1170-
freezable, code must explicitly make it so, through an
1171-
``@frozen`` (at definition-time), ``@freezable`` opting in to
1172-
being frozen as a side-effect of freezing an instance, or through
1173-
an explicit call to ``freeze()`` on the type object itself. This
1174-
serves as documentation similar to the ``const`` propagation
1200+
immutable, code must explicitly make it so, through a ``@frozen``
1201+
decorator at definition-time, or through an explicit call to ``freeze()``
1202+
on the type object itself. By using ``@freezable`` a declaration opts
1203+
in to being frozen as a side-effect of freezing an instance.
1204+
(A call to ``set_freezable(cls, Yes)`` has the same effect).
1205+
This serves as documentation similar to the ``const`` propagation
11751206
above, even though -- as Python is a dynamically checked language --
11761207
this ``const``-like propagation will be driven by run-time errors
11771208
rather than compile-time.
@@ -1242,8 +1273,8 @@ and a proxy mode for modules.
12421273

12431274
**Freezing rules:**
12441275

1245-
- Objects which are explicitly freezable (this includes all type
1246-
objects) must be frozen explicitly -- not indirectly
1276+
- Objects which are explicit-only freezable (this includes all type
1277+
objects) must be frozen by an explicit call to ``freeze`` -- not indirectly
12471278
via freeze propagation. (Other attempts fail.)
12481279
- Freezing an object graph fails if it contains objects that cannot be frozen.
12491280
- An individual object can be made impossible to freeze by setting
@@ -1397,7 +1428,7 @@ freeze.
13971428
Dealing with cyclic dependencies
13981429
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13991430

1400-
Objects that are explicitly freezable can be in a cyclic
1431+
Objects that require explicit freezing can be in a cyclic
14011432
dependency.
14021433

14031434
.. code-block:: python
@@ -1412,10 +1443,10 @@ dependency.
14121443
self.value = A()
14131444
14141445
Notably, freezing ``A`` freezes ``A.foo`` which captures ``B``.
1415-
However, since ``B`` is explicitly freezable, freezing ``A.foo``
1446+
However, since ``B`` requires explicit freezing, freezing ``A.foo``
14161447
will fail. Trying to first freeze ``B`` does not solve the
14171448
problem, as ``B.bar`` fails to freeze ``A`` which is also
1418-
explicitly freezable. The solution to this problem is to let
1449+
requires explicit freezing. The solution to this problem is to let
14191450
``freeze`` take multiple arguments which can be used to resolve
14201451
these kinds of situations: ``freeze(A, B)`` will permit ``A.foo``
14211452
to capture ``B`` because it sees that ``B`` is in the list of

0 commit comments

Comments
 (0)