PEP 695 proposes a new syntax for type parameters.
The motivation is that the scoping rules for type parameters are hard to understand,
are prone to misuse because of that, and that it forces developers to understand variance.
These are reasonable points. Type parameters can be hard to use.
However, the cure is worse than the disease.
The new scoping rules in PEP 695 are unclear and far too complicated
PEP 695 doesn’t solve the core issue that scoping rules for type parameters are hard to understand.
In fact, it makes the situation worse.
Currently, scoping is easy to understand: use the LEGB rule Python Scope & the LEGB Rule: Resolving Names in Your Code – Real Python.
The new scoping rules as described in the PEP are very hard to understand.
I would not be unable to implement PEP 695 from the PEP alone.
So we need to look at the implementation.
The implementation is large, but looking at the symbol table it appears that four new scopes are introduced, “annotation”, “typevar bound”, “type alias” and “type parameter”.
Previously there were only three: “function”, “class” and “module”.
How does more than doubling the number of scopes make anything easier to understand?
The Real Python article on scopes can be understood by any Python user: engineer, scientist, architect or student. I don’t think it would be possible to write such an accessible article covering the new scope rules.
Additional complexity in the VM.
The implementation also adds 12 instructions to the VM. Currently there are 119 instructions (not including instructions for specialization and instrumentation). That means that PEP 695 requires increasing the base instruction set by 10%. That is a lot, and totally out of proportion for any benefit it brings.
For comparison, here’s a list of some other features in terms of instructions used:
With statement: 2
Async and await: 4
Async with: 1
Async for: 1
Pattern matching: 4
Except star: 2
Walrus operator: 0
Either the PEP needs to be simplified w.r.t to scopes a lot, or the implementation is taking the wrong approach.
Whichever it is, this shouldn’t be added in 3.12.
The function object
Any use of inner function and list comprehensions (until PEP 709) creates a new function object.
The PEP 695 implementation also adds four fields to the function object struct.
The function object is important for performance and streamlining these objects is important for performance. We have put a lot of work into reducing the size of core objects and streamlining their construction and destruction. It is vexing to have this undone for a feature of such limited benefit.
Understanding scopes is key to understanding Python.
Making the scoping rules more complex limits who can understand, and therefore use, Python.
I believe that the simplicity of Python is fundamental to its popularity and will continue to be so.
Adding features that make it less accessible and harder to learn is going to hurt all of us, even the professional developers who might benefit from more powerful features like PEP 695.
Any change to the language should be in proportion to the benefit it brings.
Type variables aren’t that commonly used. If we really feel that changes are needed, then we need to work hard to make sure that those changes are in proportion to the benefit they provide.