From bbc91a9b649860387962de3c3733f18006db3f8b Mon Sep 17 00:00:00 2001 From: Philippe PRADOS Date: Mon, 2 Dec 2019 22:23:33 +0100 Subject: [PATCH] Pep 0604 : Various updates; GenericAlias impact, and rewrite objections section (#1194) --- pep-0604.rst | 122 +++++++++++++++++---------------------------------- 1 file changed, 41 insertions(+), 81 deletions(-) diff --git a/pep-0604.rst b/pep-0604.rst index 8b0007947..b28a0c75e 100644 --- a/pep-0604.rst +++ b/pep-0604.rst @@ -23,7 +23,7 @@ Motivation PEP 484 and PEP 526 propose a generic syntax to add typing to variables, parameters and function returns. PEP 585 proposes to `expose parameters to generics at runtime `_. -MyPy [4]_ accepts a syntax which looks like something like this:: +MyPy [1]_ accepts a syntax which looks like:: annotation: name_type name_type: NAME (args)? @@ -37,8 +37,8 @@ The verbosity of this syntax does not help the adoption. Proposal ======== -Inspired by Scala language [5]_, this proposal adds operator ``type.__or__()``. -With this new operator, it is possible to write ``int | str`` in place of +Inspired by Scala language [2]_ and Pike [3]_, this proposal adds operator ``type.__or__()``. +With this new operator, it is possible to write ``int | str`` instead of ``Union[int,str]``. The result of this expression would then be valid in ``isinstance()`` and ``issubclass()``:: @@ -65,14 +65,21 @@ Here are some examples of what we can do with this feature. assert isinstance("", int | str) assert issubclass(bool, int | float) -Once the Python language is extended, MyPy [4]_ and other type checkers will +Once the Python language is extended, MyPy [1]_ and other type checkers will need to be updated to accept this new syntax. +Technical point of view +======================= +To accept to extend ``isinstance()`` and ``issubclass()``, the object ``_GenericAlias`` must be available as a core, +that doesn't have a directly-accessible name but via alias in typing module.. + Incompatible changes ==================== In some situations, some exceptions will not be raised as expected. +For backward compatibility, ``typing.py`` must say ``_GenericAlias = _GenericAlias``. + If a metaclass implements the ``__or__`` operator, it will override this:: >>> class M(type): @@ -90,71 +97,34 @@ If a metaclass implements the ``__or__`` operator, it will override this:: Objections and responses ======================== +For more details about discussions, see links below: + - `Discussion in python-ideas `_ - `Discussion in typing-sig `_ 1. Add a new operator for ``Union[type1|type2]``? ------------------------------------------------- -- CONS: This is not a new proposal. If I recall correctly, it was proposed way back at the very beginning of the - type-hinting discussion, and there has been at least one closed feature request for it: - `Issue 387 `_ +PROS: - - It is maybe too late to change this, many people are already get used to current notation. +- This syntax can be more readable, and is similary to others languages (Scala, ...) +- At runtime, ``int|str`` might return a simple object in 3.9, rather than everything that + you'd need to grab from importing ``typing`` - - *This PEP propose to add a new notation, not to replace the notation* - - This syntax is difficult to google, if someone encounters it in code - - It is still not possible to use ``|`` for unions because of built-in types. (This would require a corresponding - slot in type which is a non-starter) +CONS: - - *The proposed implementation do it* +- Adding this operator introduce a dependency between ``typing`` and ``builtins`` +- As breaking the backport (in that ``typing`` can easily be backported but core ``types`` can't) +- If Python itself doesn't have to be changed, we'd still need to implement it in mypy, Pyre, PyCharm, + Pytype, and who knows what else (it's a minor change see "Reference Implementation" - - There are currently no volunteer to implement this in mypy - - - *An implementation is proposed now (One patch for CPython and one for MyPy).* - - - "but as @ilevkivskyi pointed out, that is not an option (at least until Python 4)." - - - *Is it time now ?* - -- PRO: It's similar of Scala -- PRO: Seems like ``foo | None`` is just as readable -- PRO: Which means you couldn't use this feature in Python 3.7, much less 2.7. I'm not sure it maintaining backward - compatibility in typing and in mypy is still as important today as it was 5 years ago, but I'm pretty sure it hasn't - been abandoned entirely. -- CONS: add operator introducing a dependency to typing in builtins -- CONS: supporting this would likely break compatibility with existing code that overloads ``|`` for class objects - using a metaclass. We could perhaps work around this by making ``|`` inside an annotation context different from - the regular ``|`` operator. - - - *A work around is to use* ``Union[type1,type2]`` *in this case* - -- CONS: You need ``__ror__`` as well as ``__or__`` - - *No, in this situation, Python auto invoke ``__or__`` in case of ``__ror__``.* -- CONS: as breaking the backport (in that ``typing.py`` can easily be backported but core ``types`` can't) - - - There are several things in the typing syntax that require a certain minimum version. E.g. type annotations require - Python 3 (whereas type comments work in Python 2 too), type annotations on variables (PEP 526) require 3.6+, - ``from __future__ import annotations`` (PEP 563) requires 3.7+. - -- PRO: I mean that at run-time, ``int|str`` might return a very simple object in 3.9, rather than everything that - you'd need to grab from importing ``typing``. Wondering if doing so would close off the possibility of, in 3.12 or - something, making it a more directly usable "type union" that has other value. -- CONS: if Python itself doesn't have to be changed, we'd still need to implement it in mypy, Pyre, PyCharm, - Pytype, and who knows what else. - - - *A proposed patch of mypy is just 20 lines of codes* - -- If yes, [??? incomplete?] Change only the PEP 484 (Type hints) to accept the syntax ``type1 | type2`` ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- PRO: PEP 563 (Postponed Evaluation of Annotations) is enough to accept this proposition -- CONS: The Resolving type hints at runtime says: “For code which uses annotations for other purposes, a - regular ``eval(ann, globals, locals)`` call is enough to resolve the annotation.". Without add a new - operator ``__or__`` in type ``type``, it's not possible to resolve type hints at runtime. +PEP 563 (Postponed Evaluation of Annotations) is enough to accept this proposition, +if we accept to not be compatible with the dynamic evaluation of annotations (``eval()``). :: @@ -167,26 +137,6 @@ Change only the PEP 484 (Type hints) to accept the syntax ``type1 | type2`` ? File "", line 1, in TypeError: unsupported operand type(s) for |: 'type' and 'type' - - CONS: Without operator, it's not possible to write - -:: - - >>> u = int | str - >>> u - typing.Union[int, str] - -Use ``(int, str)`` in place of ``Union[int,str]`` ? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- PRO: This doesn't have compatibility issues and it's similar to ``isinstance(foo, (int, str))`` -- PRO: Either better than breaking backward compatibility by adding new operator methods to the type ``type``. -- CONS: In most languages with similar-ish type syntax, ``(int, str)`` means ``Tuple[int, str]``, - not ``Union[int, str]``. - -Use ``{int, str}`` in place of ``Union[int,str]`` ? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- PRO: big advantage of ``{int, str}`` over ``int|str``. It doesn't require adding anything to ``type``, - and we don't need to introduce a new lightweight builtin union type. - 2. Extend ``isinstance()`` and ``issubclass()`` to accept ``Union`` ? --------------------------------------------------------------------- @@ -194,32 +144,42 @@ Use ``{int, str}`` in place of ``Union[int,str]`` ? isinstance(x, str | int) ==> "is x an instance of str or int" -- PRO: if they were permitted, then instance checks could use an extremely clean-looking notation for "any of these": -- PRO: The implementation can use the tuple present in ``Union`` parameter, without create a new instance. +PROS: + +- If they were permitted, then instance checking could use an extremely clean-looking notation +- The implementation can use the tuple present in ``Union`` parameter, without create a new instance + +CONS: + +- Must migrate all the ``typing`` module in ``builtin`` + Reference Implementation ======================== A proposed implementation for `cpython is here -`_. +`_. A proposed implementation for `mypy is here -`_. +`_. References ========== -.. [4] MyPy +.. [1] MyPy http://mypy-lang.org/ -.. [5] Scala Union Types +.. [2] Scala Union Types https://dotty.epfl.ch/docs/reference/new-types/union-types.html +.. [3] Pike + http://pike.lysator.liu.se/docs/man/chapter_3.html#3.5 + Copyright ========= This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive. - + .. Local Variables: mode: indented-text