Dynamically Checked Deep Immutability in Python
- Fridtjof Stoldt ,
- Sylvan Clebsch ,
- Matthew Johnson ,
- Matthew J. Parkinson ,
- Tobias Wrigstad
Proceedings of the ACM on Programming Languages | , Vol 10 (PLDI): pp. 2623-2646
Immutability is common in the programming mainstream: deep immutability is the default in functional languages while imperative languages typically provide opt-in support for shallow immutability, usually enforced through static checking.
Python is a dynamic imperative language where mutability is inherent: not only are most objects mutable, but programs themselves—modules, classes, functions—are represented by mutable objects at run-time, and libraries routinely rely on this mutability. This makes adding immutability to Python a significant challenge.
This paper presents the design and implementation of deep immutability for Python. Our primary motivation is to permit multiple sub-interpreters to directly share object references, which currently requires costly serialisation. Sharing via immutability introduces a soundness challenge, as a violation could corrupt the interpreter’s state.
We identify numerous challenges that stem from decades of design decisions that did not anticipate immutability, and show how they can be overcome through two complementary techniques: detachment, which severs run-time links that would cause immutability to propagate too widely, and freezability, which gives objects run-time control over whether and how they may become immutable. Together, these principles form a general design pattern for deep immutability in dynamic languages. We validate our design with an implementation on CPython 3.15 that is backwards-compatible with existing programs and enables direct, zero-copy sharing of immutable objects across sub-interpreters.