Typing Stability & Evolution

I think there’s a lot of confusion in this and related threads. I’d like to take the opportunity to draw a distinction between a) stability of the type system, b) stability of the day-to-day experience of using a type checker.

These two are very different! PEP 724 is about the former, but what comes to mind for most people is the latter.


First off, we do not change semantics of special symbols. Such symbols are introduced by PEPs and their behaviour is usually standardised to the extent specified in the PEPs. PEP 724 is to my knowledge the only typing PEP that has proposed a backwards incompatible change of semantics of a symbol. Let’s not overfit to a single example.

If a backwards incompatible change were to be made, it would have to be a PEP, which this is. And if it were a PEP, the backwards incompatibility would have to be seriously considered, which it is. See
this message from Jelle — we’re unlikely to actually make the backwards incompatible change.

(I’ll concede the exact nature of backward incompatibility matters. If this changed behaviour at runtime no one would even have written the PEP)
(I’ll also readily concede that PEPs insufficiently specify behaviour and am working to change that, but in practice this matters little to most existing users. Note in the PEP 724 case, the relevant behaviour is specified in 647)

experimental features may have to do something like from typing_extensions import Intersection

You’ll be happy to know we already do this; in fact, type checkers even have their own extension libraries (see mypy_extensions and pyre_extensions). But sometimes this process doesn’t raise issues to the extent that they result in change, in which case you can end up having a discussion like PEP 724.


Now what does happen frequently is minor changes to type checker behaviour, as mentioned here. These are usually fixing of bugs, or allowing the type checker to understand just a little more of Python code.

Here is a representative example. I make a change that allows mypy to better understand code (specifically objects with __call__ that is overloaded with a generic self type). mypy_primer reports that it gets rid of one unnecessary error in 10 million lines of code. Or maybe more relevant to pip, typeshed will make a change to more accurately reflect that email.message.Message.get* can return None. Add up enough times, and you’ll have to move around a few # type: ignore when you change type checker versions.

You can criticise mypy or typeshed for being too cavalier about these changes, or for being bad software or whatever. But confusing this kind of instability for type system instability is akin to saying “Various semantics of pip are governed by PEPs, therefore pip shouldn’t make user visible behaviour changes without following the same processes as Python”. This kind of criticism also better belongs on issue trackers.

10 Likes