Skip to content

Commit 6e49cec

Browse files
ppradosRosuav
authored andcommitted
Pep 0604: Remove __revert__ operator (#1183)
* Add PEP-0604 to describes an extension to Python language, which aims to add a complementary syntax to write ``Union[X,Y]`` and ``Optional[X]`` easier. * Add sample with metaclass with __invert__ and/or __or__ * Remove operator __revert__
1 parent 16bc282 commit 6e49cec

File tree

1 file changed

+20
-100
lines changed

1 file changed

+20
-100
lines changed

pep-0604.rst

Lines changed: 20 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Introduction
1313
============
1414

1515
This PEP describes an extension to Python language, which aims to add a complementary
16-
syntax to write ``Union[X,Y]`` and ``Optional[X]`` easier.
16+
syntax to write ``Union[X,Y]`` easier.
1717

1818

1919
Motivation
@@ -33,45 +33,14 @@ MyPy [4]_ accepts a syntax which looks like something like this:
3333

3434
- To describe a disjunction, the user must use ``Union[X,Y]``.
3535

36-
- To describe an optional value, the user must use ``Optional[X]``.
37-
3836
The verbosity of this syntax does not help the adoption.
3937

4038
Proposal
4139
========
4240

43-
Inspired by Scala language [5]_, this proposal adds two operators in the root ``type``:
44-
45-
Strong proposition
46-
------------------
47-
Add operator ``__or__()`` in the root ``type``.
48-
41+
Inspired by Scala language [5]_, this proposal adds operator ``__or__()`` in the root ``type``.
4942
With this new operator, it is possible to write ``int | str`` in place of ``Union[int,str]``.
50-
5143
This proposition uses the standard meaning of the ``|`` operator.
52-
53-
Optional proposition 1
54-
----------------------
55-
Add operator ``__invert__()`` in the root ``type``.
56-
57-
With this new operator, it is possible to write ``~int`` in place of ``Optional[int]``.
58-
59-
This proposition uses this operator because it is present in the language and it's conform to the
60-
`usage of tilde <https://www.thecut.com/article/why-the-internet-tilde-is-our-most-perfect-tool-for-snark.html>`_
61-
62-
So, the new syntax for annotations will be:
63-
64-
::
65-
66-
annotation: ( name_type | or_type | invert_type )
67-
or_type: name_type '|' annotation
68-
invert_type: '~' annotation
69-
name_type: NAME (args)?
70-
args: '[' paramslist ']'
71-
paramslist: annotation (',' annotation)* [',']
72-
73-
Optional proposition 2
74-
----------------------
7544
Then, it is possible to extend ``isinstance()`` and ``issubclass()``
7645
to accept this new syntax:
7746

@@ -88,14 +57,13 @@ Here are some examples of what we can do with this feature.
8857

8958
# in place of
9059
# def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]
91-
def f(list: List[int | str], param: ~int) -> float | str:
60+
def f(list: List[int | str], param: int | None) -> float | str:
9261
pass
9362

9463
f([1,"abc"],None)
9564

9665
assert str | int == Union[str,int]
9766
assert str | int | float == Union[str, int, float]
98-
assert ~str == Optional[str]
9967

10068
assert isinstance("", int | str)
10169
assert issubclass(int, int | str)
@@ -106,11 +74,26 @@ Incompatible changes
10674
====================
10775
In some situations, some exceptions will not be raised as expected.
10876

77+
If some metaclass overload the ``__or__`` operator, the user must resolve the ambiguities with ``Union``.
78+
::
79+
80+
>>> class M(type):
81+
... def __or__(self,other): return "Hello"
82+
...
83+
>>> class C(metaclass=M):pass
84+
...
85+
>>> C | int
86+
'Hello'
87+
>>> int | C
88+
typing.Union[int, __main__.C]
89+
>>> Union[C,int]
90+
typing.Union[__main__.C, int]
10991

11092
Dissenting Opinion
11193
==================
11294

11395
- `Discussion in python-ideas <https://mail.python.org/archives/list/[email protected]/thread/FCTXGDT2NNKRJQ6CDEPWUXHVG2AAQZZY/>`_
96+
- `Discussion in typing-sig <https://mail.python.org/archives/list/[email protected]/thread/D5HCB4NT4S3WSK33WI26WZSFEXCEMNHN/>`_
11497

11598
1. Add a new operator for ``Union[type1|type2]``?
11699
--------------------------------------------------
@@ -206,69 +189,7 @@ Use ``{int, str}`` in place of ``Union[int,str]`` ?
206189
- PRO: big advantage of ``{int, str}`` over ``int|str``. It doesn't require adding anything to ``type``,
207190
and we don't need to introduce a new lightweight builtin union type.
208191

209-
2. Add a new operator for ``Optional[type]`` ?
210-
----------------------------------------------
211-
212-
- CONS: ``foo | None`` is short and readable
213-
- CONS: ``foo | None`` it's 3 fewer characters than ``Optional[foo]``, or 30 fewer if you include the full
214-
removal of ``from typing import Optional``. the additional gain of ``~foo`` is only 6 characters.
215-
- PRO: help the readability, with a lot of parameters:
216-
217-
::
218-
219-
def f(source: str | None, destination: str | None, param: int | None):...
220-
def f(source: ~str, destination: ~str, param: ~int):...
221-
222-
- PRO: I'm currently working on annotating a very large codebase, and ``Optional[T]`` is so frequent that I
223-
think ``T | None`` would not be enough of an improvement.
224-
- PRO: Adding a default ``__or__`` overload to ``type`` seems a reasonable price to pay in 3.9, and
225-
ditto for ``__invert__``. Type checkers can support this in older Python versions using PEP 563 or in type
226-
comments or in "forward references" (types hidden in string literals).
227-
- CONS: The ``~`` is easy to be missed (at least by human readers) and the meaning not obvious.
228-
- PRO: Also, Python's typing system is a lot easier to grasp if you're familiar with an established modern-typed
229-
language (Swift, Scala, Haskell, F#, etc.), and they also use ``Optional[T]`` (or ``optional<T>`` or ``Maybe t``
230-
or some other spelling of the same idea) all over be place—so often that many of them have added shortcuts
231-
like ``T?`` to make it easier to write and less intrusive to read.
232-
233-
- if yes,
234-
235-
Add operator ``__revert__`` in type type to use syntax like ``~int`` ?
236-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
237-
- CONS: ``~`` is not automatically readable
238-
239-
- *like ``:`` to separate variable and typing.*
240-
241-
- CONS: ``~`` means complement, which is a completely different thing from ``|None``. ``~int`` seems like it
242-
would actually harm comprehension instead of helping.
243-
- PRO: the slight abuse of ``~int`` meaning "maybe int" is pretty plausible (consider how "approximately equal"
244-
is written mathematically).
245-
- PRO: `Possibly relevant for tilde <https://www.thecut.com/article/why-the-internet-tilde-is-our-most-perfect-tool-for-snark.html>`_
246-
- CONS: With ``~`` there probably won't be a confusion in that sense, but someone reading it for the first time will
247-
definitely need to look it up (which is fine i.m.o.).
248-
249-
- *Like the first time someone reading the annotation*
250-
251-
::
252-
253-
def f(a=int):...
254-
def f(a:int):...
255-
256-
Add operator ``__add__`` in type type to use syntax like ``+int`` ?
257-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
258-
- PRO: ``+foo`` definitely seems to say "foo, plus something else" to me much more than ``~foo``.
259-
- CONS: ``+foo`` is less intuitive than ``~foo`` for ``Optional``
260-
261-
Like Kotlin, add a new ``?`` operator to use syntax like ``int?`` or ``?int`` ?
262-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
263-
264-
- CONS: It's not compatible with IPython and Jupyter Lab ``?smth`` displays help for symbol ``smth``
265-
- CONS: With default arguments, ``?=`` looks... not great
266-
267-
::
268-
269-
def f(source: str?=def_src, destination: str?=MISSING, param: int?=1): ...
270-
271-
3. Extend ``isinstance()`` and ``issubclass()`` to accept ``Union`` ?
192+
2. Extend ``isinstance()`` and ``issubclass()`` to accept ``Union`` ?
272193
---------------------------------------------------------------------
273194

274195
::
@@ -277,13 +198,12 @@ Like Kotlin, add a new ``?`` operator to use syntax like ``int?`` or ``?int`` ?
277198

278199
- PRO: if they were permitted, then instance checks could use an extremely clean-looking notation for "any of these":
279200
- PRO: The implementation can use the tuple present in ``Union`` parameter, without create a new instance.
280-
- CONS: Why not accept this syntax in ``except`` ?
281201

282202
Reference Implementation
283203
========================
284204

285205
A proposed implementation for `cpython is here
286-
<https://github.com/pprados/cpython/tree/updage_isinstance>`_.
206+
<https://github.com/pprados/cpython/tree/update_isinstance>`_.
287207
A proposed implementation for `mypy is here
288208
<https://github.com/pprados/mypy/tree/add_INVERT_to_types>`_.
289209

0 commit comments

Comments
 (0)