Discussions-To PEP-0604: Complementary syntax for Union[] and Optional[]

Hello everybody,
I just publish the PEP-0604 https://www.python.org/dev/peps/pep-0604/ for discussions (https://www.python.org/dev/peps/pep-0604/).
Scala 3 propose a new syntax for Union type. See here https://dotty.epfl.ch/docs/reference/new-types/union-types.html. I propose to add a similar syntax in Python.
# Operator for Union assert( int | str == Union[int,str]) assert( int | str | float == Union[int,str,float]) # Operator for Optional assert( ~int == Optional[int])
Now, it's possible to write:
def fn(bag:List[int | str], option: ~int = None) -> float | str: ...
in place of
def fn(bag:List[Option[int,str]], option: Optional[int] = None) -> Union[float,str]: ...
The discussion on python-new@python.org here https://mail.python.org/archives/list/python-ideas@python.org/thread/FCTXGDT2NNKRJQ6CDEPWUXHVG2AAQZZY/ have emerged the idea of extending also issubclass() and isinstance().
isinstance(int, int | str)
I think these syntaxes are more clear, and can help with the adoption of typing.
I test and implement these ideas in a two fork : One for CPython https://github.com/pprados/cpython/tree/updage_isinstance and one for MyPy https://github.com/pprados/mypy/tree/add_INVERT_to_types. See the branches add_OR_to_types (for Union syntax), add_INVERT_to_types (for Union and Optional syntax) or updage_isinstance (for new isinstance() and issubclass()).
How I implement that ? I add the operators __or__ and __revert__ to PyType_Type. The C code is similar of :
from typing import * def type_or(self,right): return Union[self,right] type(type).__or__ = type_or
with some check before return Union.
Actually, the accepted BNF syntax for typing is :
annotation: name_type name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
I propose to extend the BNF syntax to :
annotation: ( name_type | or_type | invert_type ) name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
or_type: name_type '|' annotation
invert_type: '~' annotation
Your remarks are welcome. Philippe Prados

For me the feeling is that the ? denotes better optional, ~int to me feels more like not int... than int or None :-)
On Fri, Sep 20, 2019 at 10:19 AM Philippe Prados philippe.prados@gmail.com wrote:
Hello everybody,
I just publish the PEP-0604 https://www.python.org/dev/peps/pep-0604/ for discussions (https://www.python.org/dev/peps/pep-0604/).
Scala 3 propose a new syntax for Union type. See here https://dotty.epfl.ch/docs/reference/new-types/union-types.html. I propose to add a similar syntax in Python.
# Operator for Union assert( int | str == Union[int,str]) assert( int | str | float == Union[int,str,float]) # Operator for Optional assert( ~int == Optional[int])
Now, it's possible to write:
def fn(bag:List[int | str], option: ~int = None) -> float | str: ...
in place of
def fn(bag:List[Option[int,str]], option: Optional[int] = None) -> Union[float,str]: ...
The discussion on python-new@python.org here https://mail.python.org/archives/list/python-ideas@python.org/thread/FCTXGDT2NNKRJQ6CDEPWUXHVG2AAQZZY/ have emerged the idea of extending also issubclass() and isinstance().
isinstance(int, int | str)
I think these syntaxes are more clear, and can help with the adoption of typing.
I test and implement these ideas in a two fork : One for CPython https://github.com/pprados/cpython/tree/updage_isinstance and one for MyPy https://github.com/pprados/mypy/tree/add_INVERT_to_types. See the branches add_OR_to_types (for Union syntax), add_INVERT_to_types (for Union and Optional syntax) or updage_isinstance (for new isinstance() and issubclass()).
How I implement that ? I add the operators __or__ and __revert__ to PyType_Type. The C code is similar of :
from typing import * def type_or(self,right): return Union[self,right] type(type).__or__ = type_or
with some check before return Union.
Actually, the accepted BNF syntax for typing is :
annotation: name_type name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
I propose to extend the BNF syntax to :
annotation: ( name_type | or_type | invert_type ) name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
or_type: name_type '|' annotation
invert_type: '~' annotation
Your remarks are welcome. Philippe Prados _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

On 20 Sep 2019, at 11:38, Bernat Gabor gaborjbernat@gmail.com wrote:
For me the feeling is that the ? denotes better optional, ~int to me feels more like not int... than int or None :-)
On Fri, Sep 20, 2019 at 10:19 AM Philippe Prados philippe.prados@gmail.com wrote: Hello everybody,
I just publish the PEP-0604 for discussions (https://www.python.org/dev/peps/pep-0604/). Scala 3 propose a new syntax for Union type. See here. I propose to add a similar syntax in Python. # Operator for Union assert( int | str == Union[int,str]) assert( int | str | float == Union[int,str,float]) # Operator for Optional assert( ~int == Optional[int]) Now, it's possible to write: def fn(bag:List[int | str], option: ~int = None) -> float | str: ... in place of def fn(bag:List[Option[int,str]], option: Optional[int] = None) -> Union[float,str]: ...
The discussion on python-new@python.org here have emerged the idea of extending also issubclass() and isinstance(). isinstance(int, int | str) I think these syntaxes are more clear, and can help with the adoption of typing. I test and implement these ideas in a two fork : One for CPython and one for MyPy. See the branches add_OR_to_types (for Union syntax), add_INVERT_to_types (for Union and Optional syntax) or updage_isinstance (for new isinstance() and issubclass()). How I implement that ? I add the operators __or__ and __revert__ to PyType_Type. The C code is similar of : from typing import * def type_or(self,right): return Union[self,right] type(type).__or__ = type_or with some check before return Union. Actually, the accepted BNF syntax for typing is : annotation: name_type name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [','] I propose to extend the BNF syntax to : annotation: ( name_type | or_type | invert_type ) name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [','] or_type: name_type '|' annotation invert_type: '~' annotation Your remarks are welcome. Philippe Prados _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
I have a similar feeling. I’d read ~int as “not int” or “kinda int”, depending on the context, but not really “optionally int”.
That said I like the Union syntax and I believe it’s a nice feature from a Python programmer’s point of view.
Best regards, Jakub

Yes, but ? is used by IPython :-(
Le ven. 20 sept. 2019 à 11:38, Bernat Gabor gaborjbernat@gmail.com a écrit :
For me the feeling is that the ? denotes better optional, ~int to me feels more like not int... than int or None :-)
On Fri, Sep 20, 2019 at 10:19 AM Philippe Prados < philippe.prados@gmail.com> wrote:
Hello everybody,
I just publish the PEP-0604 https://www.python.org/dev/peps/pep-0604/ for discussions (https://www.python.org/dev/peps/pep-0604/).
Scala 3 propose a new syntax for Union type. See here https://dotty.epfl.ch/docs/reference/new-types/union-types.html. I propose to add a similar syntax in Python.
# Operator for Union assert( int | str == Union[int,str]) assert( int | str | float == Union[int,str,float]) # Operator for Optional assert( ~int == Optional[int])
Now, it's possible to write:
def fn(bag:List[int | str], option: ~int = None) -> float | str: ...
in place of
def fn(bag:List[Option[int,str]], option: Optional[int] = None) -> Union[float,str]: ...
The discussion on python-new@python.org here https://mail.python.org/archives/list/python-ideas@python.org/thread/FCTXGDT2NNKRJQ6CDEPWUXHVG2AAQZZY/ have emerged the idea of extending also issubclass() and isinstance().
isinstance(int, int | str)
I think these syntaxes are more clear, and can help with the adoption of typing.
I test and implement these ideas in a two fork : One for CPython https://github.com/pprados/cpython/tree/updage_isinstance and one for MyPy https://github.com/pprados/mypy/tree/add_INVERT_to_types. See the branches add_OR_to_types (for Union syntax), add_INVERT_to_types (for Union and Optional syntax) or updage_isinstance (for new isinstance() and issubclass()).
How I implement that ? I add the operators __or__ and __revert__ to PyType_Type. The C code is similar of :
from typing import * def type_or(self,right): return Union[self,right] type(type).__or__ = type_or
with some check before return Union.
Actually, the accepted BNF syntax for typing is :
annotation: name_type name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
I propose to extend the BNF syntax to :
annotation: ( name_type | or_type | invert_type ) name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
or_type: name_type '|' annotation
invert_type: '~' annotation
Your remarks are welcome. Philippe Prados _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

Am 20.09.19 um 11:19 schrieb Philippe Prados:
I just publish the PEP-0604 https://www.python.org/dev/peps/pep-0604/ for discussions (https://www.python.org/dev/peps/pep-0604/).
I'm strongly in favor of a more succinct syntax for both Union and Optional. But just to add my own bike-shedding to it: I prefer using the "or" operator over the "|" operator for Union. This feels more in line with existing Python operators and the preference for speaking code. "or" is the logical OR, while "|" is used for bit-wise operations. "x: int or str" is also quite intuitive. I also echo the sentiments of using "~" for Optional. As the bit-wise inversion operator it has quite a different meaning at the moment.
- Sebastian

It's not possible now, before the PEP 335 https://www.python.org/dev/peps/pep-0335/ was accepted, to overload the "or" operator.
Le ven. 20 sept. 2019 à 14:41, Sebastian Rittau srittau@rittau.biz a écrit :
Am 20.09.19 um 11:19 schrieb Philippe Prados:
I just publish the PEP-0604 https://www.python.org/dev/peps/pep-0604/ for discussions (https://www.python.org/dev/peps/pep-0604/).
I'm strongly in favor of a more succinct syntax for both Union and Optional. But just to add my own bike-shedding to it: I prefer using the "or" operator over the "|" operator for Union. This feels more in line with existing Python operators and the preference for speaking code. "or" is the logical OR, while "|" is used for bit-wise operations. "x: int or str" is also quite intuitive. I also echo the sentiments of using "~" for Optional. As the bit-wise inversion operator it has quite a different meaning at the moment.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

On Fri, Sep 20, 2019 at 10:41 PM Sebastian Rittau srittau@rittau.biz wrote:
Am 20.09.19 um 11:19 schrieb Philippe Prados:
I just publish the PEP-0604 for discussions (https://www.python.org/dev/peps/pep-0604/).
I'm strongly in favor of a more succinct syntax for both Union and Optional. But just to add my own bike-shedding to it: I prefer using the "or" operator over the "|" operator for Union. This feels more in line with existing Python operators and the preference for speaking code. "or" is the logical OR, while "|" is used for bit-wise operations. "x: int or str" is also quite intuitive. I also echo the sentiments of using "~" for Optional. As the bit-wise inversion operator it has quite a different meaning at the moment.
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
ChrisA

Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian

The Resolving type hints at runtime https://www.python.org/dev/peps/pep-0563/#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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

I'd like to see a backward compatibility concern highlighted in the PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados philippe.prados@gmail.com wrote:
The Resolving type hints at runtime https://www.python.org/dev/peps/pep-0563/#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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

Code that defines dunder methods on meta classes is likely already broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile asottile@umich.edu wrote:
I'd like to see a backward compatibility concern highlighted in the PEP
given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados philippe.prados@gmail.com wrote:
The Resolving type hints at runtime
https://www.python.org/dev/peps/pep-0563/#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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz
a
écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater
changes.
The definition of the "or" operator is baked into the language,
but
the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a
fine
limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

how so? I don't see how this interferes at all unless the metaclass is trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer markus@unterwaditzer.net wrote:
Code that defines dunder methods on meta classes is likely already broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile < asottile@umich.edu> wrote:
I'd like to see a backward compatibility concern highlighted in the PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados < philippe.prados@gmail.com> wrote:
The Resolving type hints at runtime https://www.python.org/dev/peps/pep-0563/#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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass is trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer markus@unterwaditzer.net wrote: Code that defines dunder methods on meta classes is likely already broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile asottile@umich.edu wrote: I'd like to see a backward compatibility concern highlighted in the PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados philippe.prados@gmail.com wrote: 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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a écrit : Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

generic of T where T defines __getitem__ is not a problem, I don't see your point
On Fri, Sep 20, 2019, 10:07 PM Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass is
trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer <
markus@unterwaditzer.net> wrote:
Code that defines dunder methods on meta classes is likely already
broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile <
asottile@umich.edu> wrote:
I'd like to see a backward compatibility concern highlighted in the PEP
-- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados <
philippe.prados@gmail.com> wrote:
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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a
écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

I checked the impacts with the meta-classes.
class M(type):
... def __or__(self,other): return "Hello" ... def __invert__(self): return "World" ...
class C(metaclass=M):pass
...
C | int
'Hello'
~C
'Word'
int | C
typing.Union[int, __main__.C]
Union[C,int]
typing.Union[__main__.C, int]
Because type is the top level metaclass, there is no impact of the current code. The user can continue to use the old syntax with Union, to resolve ambiguities. I add this in the new draft of the PEP https://github.com/pprados/peps/blob/pep-0604/pep-0604.rst
Philippe
Le ven. 20 sept. 2019 à 22:12, Anthony Sottile asottile@umich.edu a écrit :
generic of T where T defines __getitem__ is not a problem, I don't see your point
On Fri, Sep 20, 2019, 10:07 PM Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass is
trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer <
markus@unterwaditzer.net> wrote:
Code that defines dunder methods on meta classes is likely already
broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile <
asottile@umich.edu> wrote:
I'd like to see a backward compatibility concern highlighted in the PEP
-- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados <
philippe.prados@gmail.com> wrote:
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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a
écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

The code "works" in that it doesn't crash, but it may result in unintended import-time side-effects when an annotation was requested (an example I've seen of `|` in the wild on a metaclass is a subprocess piping library) -- and you don't get the type annotation either you end up with the type's `|` or `~` being used so `__annotations__` is wrong
On Sun, Sep 22, 2019 at 11:46 PM Philippe Prados philippe.prados@gmail.com wrote:
I checked the impacts with the meta-classes.
class M(type):
... def __or__(self,other): return "Hello" ... def __invert__(self): return "World" ...
class C(metaclass=M):pass
...
C | int
'Hello'
~C
'Word'
int | C
typing.Union[int, __main__.C]
Union[C,int]
typing.Union[__main__.C, int]
Because type is the top level metaclass, there is no impact of the current code. The user can continue to use the old syntax with Union, to resolve ambiguities. I add this in the new draft of the PEP https://github.com/pprados/peps/blob/pep-0604/pep-0604.rst
Philippe
Le ven. 20 sept. 2019 à 22:12, Anthony Sottile asottile@umich.edu a écrit :
generic of T where T defines __getitem__ is not a problem, I don't see your point
On Fri, Sep 20, 2019, 10:07 PM Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass is
trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer <
markus@unterwaditzer.net> wrote:
Code that defines dunder methods on meta classes is likely already
broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile <
asottile@umich.edu> wrote:
I'd like to see a backward compatibility concern highlighted in the
PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
> class M(type):
... def __or__(self, other): return self ...
> class C(metaclass=M): pass
...
> C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados <
philippe.prados@gmail.com> wrote:
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.
> from __future__ import annotations > def foo() -> int | str: pass
...
> eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz
a écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

My point on the operator __invert__.
- The old style string formatting https://docs.python.org/2/library/stdtypes.html#string-formatting use '%', the modulo operator. But in this context, the user can not make a mistake. I think, it is the same for toto:~int - The operator __invert__ (~) is not the best, like '?', but '?' is use by IPython and at time, Python has no operator for that. - This operator is not bad, because '~' is very little used by normal user and the usage of tilde https://www.thecut.com/article/why-the-internet-tilde-is-our-most-perfect-tool-for-snark.html is compatible with this proposition, as Guido van Rossum reminded - Why the typing propose the class Optional[T] ? I think it's because Union[T,None] is not exactly the same in the mind of the user. Optional say "Something or nothing". Union say "This type or this other type". I think the same arguments to accept the class Optional can be used to accept the operator __invert__.
Philippe
Le lun. 23 sept. 2019 à 14:38, Anthony Sottile asottile@umich.edu a écrit :
The code "works" in that it doesn't crash, but it may result in unintended import-time side-effects when an annotation was requested (an example I've seen of `|` in the wild on a metaclass is a subprocess piping library) -- and you don't get the type annotation either you end up with the type's `|` or `~` being used so `__annotations__` is wrong
On Sun, Sep 22, 2019 at 11:46 PM Philippe Prados < philippe.prados@gmail.com> wrote:
I checked the impacts with the meta-classes.
class M(type):
... def __or__(self,other): return "Hello" ... def __invert__(self): return "World" ...
class C(metaclass=M):pass
...
C | int
'Hello'
~C
'Word'
int | C
typing.Union[int, __main__.C]
Union[C,int]
typing.Union[__main__.C, int]
Because type is the top level metaclass, there is no impact of the current code. The user can continue to use the old syntax with Union, to resolve ambiguities. I add this in the new draft of the PEP https://github.com/pprados/peps/blob/pep-0604/pep-0604.rst
Philippe
Le ven. 20 sept. 2019 à 22:12, Anthony Sottile asottile@umich.edu a écrit :
generic of T where T defines __getitem__ is not a problem, I don't see your point
On Fri, Sep 20, 2019, 10:07 PM Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass
is trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer <
markus@unterwaditzer.net> wrote:
Code that defines dunder methods on meta classes is likely already
broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile <
asottile@umich.edu> wrote:
I'd like to see a backward compatibility concern highlighted in the
PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
>> class M(type):
... def __or__(self, other): return self ...
>> class C(metaclass=M): pass
...
>> C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados <
philippe.prados@gmail.com> wrote:
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.
>> from __future__ import annotations >> def foo() -> int | str: pass
...
>> eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz
a écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

I'm not convinced by this argument. %-style formatting has been superseded by new-style formatting using str.format and f-strings more recently. The PEP for new-style formatting does not mention that overloading % is confusing for people who know it as modulo, but I would not count it as endorsement of this sort of thing either.
Then there's the argument that mentions Option. I recognize that this successfully argues why we should have a shortcut for optional types at all, but to me it does not argue why ~ is a good choice. Optional as a class name does not overload existing concepts in the same way.
On 24.09.2019, at 18:37, Philippe Prados philippe.prados@gmail.com wrote:
My point on the operator __invert__. • The old style string formatting use '%', the modulo operator. But in this context, the user can not make a mistake. I think, it is the same for toto:~int • The operator __invert__ (~) is not the best, like '?', but '?' is use by IPython and at time, Python has no operator for that. • This operator is not bad, because '~' is very little used by normal user and the usage of tilde is compatible with this proposition, as Guido van Rossum reminded • Why the typing propose the class Optional[T] ? I think it's because Union[T,None] is not exactly the same in the mind of the user. Optional say "Something or nothing". Union say "This type or this other type". I think the same arguments to accept the class Optional can be used to accept the operator __invert__. Philippe
Le lun. 23 sept. 2019 à 14:38, Anthony Sottile asottile@umich.edu a écrit : The code "works" in that it doesn't crash, but it may result in unintended import-time side-effects when an annotation was requested (an example I've seen of `|` in the wild on a metaclass is a subprocess piping library) -- and you don't get the type annotation either you end up with the type's `|` or `~` being used so `__annotations__` is wrong
On Sun, Sep 22, 2019 at 11:46 PM Philippe Prados philippe.prados@gmail.com wrote: I checked the impacts with the meta-classes.
class M(type):
... def __or__(self,other): return "Hello" ... def __invert__(self): return "World" ...
class C(metaclass=M):pass
...
C | int
'Hello'
~C
'Word'
int | C
typing.Union[int, __main__.C]
Union[C,int]
typing.Union[__main__.C, int]
Because type is the top level metaclass, there is no impact of the current code. The user can continue to use the old syntax with Union, to resolve ambiguities. I add this in the new draft of the PEP
Philippe
Le ven. 20 sept. 2019 à 22:12, Anthony Sottile asottile@umich.edu a écrit : generic of T where T defines __getitem__ is not a problem, I don't see your point
On Fri, Sep 20, 2019, 10:07 PM Markus Unterwaditzer markus@unterwaditzer.net wrote: I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass is trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer markus@unterwaditzer.net wrote: Code that defines dunder methods on meta classes is likely already broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile asottile@umich.edu wrote: I'd like to see a backward compatibility concern highlighted in the PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
class M(type):
... def __or__(self, other): return self ...
class C(metaclass=M): pass
...
C | int
<class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados philippe.prados@gmail.com wrote: 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.
from __future__ import annotations def foo() -> int | str: pass
...
eval(foo.__annotations__['return'])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz a écrit : Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

On Wed, Sep 25, 2019 at 3:14 AM Markus Unterwaditzer markus@unterwaditzer.net wrote:
I'm not convinced by this argument. %-style formatting has been superseded by new-style formatting using str.format and f-strings more recently. The PEP for new-style formatting does not mention that overloading % is confusing for people who know it as modulo, but I would not count it as endorsement of this sort of thing either.
Percent formatting isn't superseded or replaced, and the new Path objects overload division in an intuitive way. There IS precedent for (ab)using operators because their symbols are appropriate.
But ~int isn't nearly as appealing to me as int|str, proposal-wise. If ~ gets dropped from this proposal, someone else can always pick it up separately and repropose it.
ChrisA

Since you mentioned my name, let me explain my current position on how to spell "optional".
- We've had a lot of feedback from mypy users who were confused by Optional[T] and thought this was needed for "optional" function arguments (i.e. those that have a default).
- Another situation where people have been confused Optional is in TypedDict, where we wanted to have a way to say "this key may be present or absent" (in the end we couldn't find a good keyword for this so we went with "total=<bool>" for the entire dict).
- It would probably have been less confusing if it had been called "nullable" (or "noneable"? Ruby's Sorbet type system calls it "nilable").
- In TypeScript you just write "int | None", and that looks readable enough to me -- and perfectly unambiguous.
So my preference would be to drop the "~" proposal (or aspirations for "?") and instead just write "int | None".
IIRC at last Friday's Bay Area typing meetup there was general agreement with this sentiment.
--Guido
On Tue, Sep 24, 2019 at 9:38 AM Philippe Prados philippe.prados@gmail.com wrote:
My point on the operator __invert__.
- The old style string formatting
https://docs.python.org/2/library/stdtypes.html#string-formatting use '%', the modulo operator. But in this context, the user can not make a mistake. I think, it is the same for toto:~int
- The operator __invert__ (~) is not the best, like '?', but '?' is
use by IPython and at time, Python has no operator for that.
- This operator is not bad, because '~' is very little used by normal
user and the usage of tilde https://www.thecut.com/article/why-the-internet-tilde-is-our-most-perfect-tool-for-snark.html is compatible with this proposition, as Guido van Rossum reminded
- Why the typing propose the class Optional[T] ? I think it's because
Union[T,None] is not exactly the same in the mind of the user. Optional say "Something or nothing". Union say "This type or this other type". I think the same arguments to accept the class Optional can be used to accept the operator __invert__.
Philippe
Le lun. 23 sept. 2019 à 14:38, Anthony Sottile asottile@umich.edu a écrit :
The code "works" in that it doesn't crash, but it may result in unintended import-time side-effects when an annotation was requested (an example I've seen of `|` in the wild on a metaclass is a subprocess piping library) -- and you don't get the type annotation either you end up with the type's `|` or `~` being used so `__annotations__` is wrong
On Sun, Sep 22, 2019 at 11:46 PM Philippe Prados < philippe.prados@gmail.com> wrote:
I checked the impacts with the meta-classes.
class M(type):
... def __or__(self,other): return "Hello" ... def __invert__(self): return "World" ...
class C(metaclass=M):pass
...
C | int
'Hello'
~C
'Word'
int | C
typing.Union[int, __main__.C]
Union[C,int]
typing.Union[__main__.C, int]
Because type is the top level metaclass, there is no impact of the current code. The user can continue to use the old syntax with Union, to resolve ambiguities. I add this in the new draft of the PEP https://github.com/pprados/peps/blob/pep-0604/pep-0604.rst
Philippe
Le ven. 20 sept. 2019 à 22:12, Anthony Sottile asottile@umich.edu a écrit :
generic of T where T defines __getitem__ is not a problem, I don't see your point
On Fri, Sep 20, 2019, 10:07 PM Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
I am thinking of code that has been written long before typing existed, and overloads __getitem__ with something else. Now if one had to define stub/typeshed files for that code and had to use generics, it would conflict.
On 20.09.2019, at 21:51, Anthony Sottile asottile@umich.edu wrote:
how so? I don't see how this interferes at all unless the metaclass
is trying to implement genericism itself
Anthony
On Fri, Sep 20, 2019, 9:48 PM Markus Unterwaditzer <
markus@unterwaditzer.net> wrote:
Code that defines dunder methods on meta classes is likely already
broken due to use of __getitem__ for generics. So there exists a precedent for not caring about such code.
On September 20, 2019 6:04:04 PM GMT+02:00, Anthony Sottile <
asottile@umich.edu> wrote:
I'd like to see a backward compatibility concern highlighted in the
PEP -- given it's possible (and likely?) that some metaclass in the wild already defines `__or__` or `__invert__` semantics
>>> class M(type): ... def __or__(self, other): return self ... >>> class C(metaclass=M): pass ... >>> C | int <class '__main__.C'>
Anthony
On Fri, Sep 20, 2019 at 7:16 AM Philippe Prados <
philippe.prados@gmail.com> wrote:
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.
>>> from __future__ import annotations >>> def foo() -> int | str: pass ... >>> eval(foo.__annotations__['return']) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'type' and 'type'
Le ven. 20 sept. 2019 à 15:35, Sebastian Rittau srittau@rittau.biz
a écrit :
Am 20.09.19 um 14:49 schrieb Chris Angelico: > Both "int or str" and "str?" have the problem that they don't work > under existing Python syntax, so they would be far greater changes. > The definition of the "or" operator is baked into the language, but > the "|" operator can have its semantics defined by the objects on > either side.
"or" works with "from __future__ import annotations", which is a
fine
limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

On Tue, 24 Sep 2019 at 13:13, Guido van Rossum guido@python.org wrote:
Since you mentioned my name, let me explain my current position on how to spell "optional".
- We've had a lot of feedback from mypy users who were confused by
Optional[T] and thought this was needed for "optional" function arguments (i.e. those that have a default).
- Another situation where people have been confused Optional is in
TypedDict, where we wanted to have a way to say "this key may be present or absent" (in the end we couldn't find a good keyword for this so we went with "total=<bool>" for the entire dict).
- It would probably have been less confusing if it had been called
"nullable" (or "noneable"? Ruby's Sorbet type system calls it "nilable").
- In TypeScript you just write "int | None", and that looks readable
enough to me -- and perfectly unambiguous.
So my preference would be to drop the "~" proposal (or aspirations for "?") and instead just write "int | None".
IIRC at last Friday's Bay Area typing meetup there was general agreement with this sentiment.
Yes, most people agreed that `~` is not a good idea, and we should just go ahead with `int | None`. Also most people agreed we may reconsider `int?` in a separate PEP later (possibly in conjunction with PEP 505). Btw, majority of people also agreed that allowing `isinstance(x, int | str)` is a good idea (mostly for type aliases that can be used both at runtime and in an annotation) assuming `isinstance(x, str | List[str])` is still an error.
If the PEP authors don't have problems with this, then I would propose to move towards discussing details of the proposed implementation.
-- Ivan

Ok. I agree.
I will split the PEP. The next version I'm going to submit propose only int | str, int | None, and isinstance(x str | int). What do you think about that ? except int | str :
Philippe Prados
Le mar. 24 sept. 2019 à 22:42, Ivan Levkivskyi levkivskyi@gmail.com a écrit :
On Tue, 24 Sep 2019 at 13:13, Guido van Rossum guido@python.org wrote:
Since you mentioned my name, let me explain my current position on how to spell "optional".
- We've had a lot of feedback from mypy users who were confused by
Optional[T] and thought this was needed for "optional" function arguments (i.e. those that have a default).
- Another situation where people have been confused Optional is in
TypedDict, where we wanted to have a way to say "this key may be present or absent" (in the end we couldn't find a good keyword for this so we went with "total=<bool>" for the entire dict).
- It would probably have been less confusing if it had been called
"nullable" (or "noneable"? Ruby's Sorbet type system calls it "nilable").
- In TypeScript you just write "int | None", and that looks readable
enough to me -- and perfectly unambiguous.
So my preference would be to drop the "~" proposal (or aspirations for "?") and instead just write "int | None".
IIRC at last Friday's Bay Area typing meetup there was general agreement with this sentiment.
Yes, most people agreed that `~` is not a good idea, and we should just go ahead with `int | None`. Also most people agreed we may reconsider `int?` in a separate PEP later (possibly in conjunction with PEP 505). Btw, majority of people also agreed that allowing `isinstance(x, int | str)` is a good idea (mostly for type aliases that can be used both at runtime and in an annotation) assuming `isinstance(x, str | List[str])` is still an error.
If the PEP authors don't have problems with this, then I would propose to move towards discussing details of the proposed implementation.
-- Ivan

Let's not do `except E1|E2`. It doesn't look like a readability improvement over `except (E1, E2)`, and I don't think there's much of a use case for having a type alias such as `E = E1|E2` that's both used in annotations and in an except clause. (If you show me real code that contradicts me I might change my mind.)
Even though exceptions are classes, their use and handling is almost completely separate from the types we use for type checking. (In contrast with isinstance(), which does play a legitimate role in type refinements.)
--Guido
On Wed, Sep 25, 2019 at 1:25 AM Philippe Prados philippe.prados@gmail.com wrote:
Ok. I agree.
I will split the PEP. The next version I'm going to submit propose only int | str, int | None, and isinstance(x str | int). What do you think about that ? except int | str :
Philippe Prados
Le mar. 24 sept. 2019 à 22:42, Ivan Levkivskyi levkivskyi@gmail.com a écrit :
On Tue, 24 Sep 2019 at 13:13, Guido van Rossum guido@python.org wrote:
Since you mentioned my name, let me explain my current position on how to spell "optional".
- We've had a lot of feedback from mypy users who were confused by
Optional[T] and thought this was needed for "optional" function arguments (i.e. those that have a default).
- Another situation where people have been confused Optional is in
TypedDict, where we wanted to have a way to say "this key may be present or absent" (in the end we couldn't find a good keyword for this so we went with "total=<bool>" for the entire dict).
- It would probably have been less confusing if it had been called
"nullable" (or "noneable"? Ruby's Sorbet type system calls it "nilable").
- In TypeScript you just write "int | None", and that looks readable
enough to me -- and perfectly unambiguous.
So my preference would be to drop the "~" proposal (or aspirations for "?") and instead just write "int | None".
IIRC at last Friday's Bay Area typing meetup there was general agreement with this sentiment.
Yes, most people agreed that `~` is not a good idea, and we should just go ahead with `int | None`. Also most people agreed we may reconsider `int?` in a separate PEP later (possibly in conjunction with PEP 505). Btw, majority of people also agreed that allowing `isinstance(x, int | str)` is a good idea (mostly for type aliases that can be used both at runtime and in an annotation) assuming `isinstance(x, str | List[str])` is still an error.
If the PEP authors don't have problems with this, then I would propose to move towards discussing details of the proposed implementation.
-- Ivan

On Wed, 25 Sep 2019 at 16:20, Guido van Rossum guido@python.org wrote:
Let's not do `except E1|E2`
I agree with this. This feels much less valuable, and will likely cause implementation "friction".
-- Ivan

I just publish a new version of PEP-604 with only the __or__ operator.
I thinks, now, it's can be accepted. What is the next step ?
Philippe
Le sam. 28 sept. 2019 à 21:29, Ivan Levkivskyi levkivskyi@gmail.com a écrit :
On Wed, 25 Sep 2019 at 16:20, Guido van Rossum guido@python.org wrote:
Let's not do `except E1|E2`
I agree with this. This feels much less valuable, and will likely cause implementation "friction".
-- Ivan

On Tue, Oct 1, 2019 at 11:18 PM Philippe Prados philippe.prados@gmail.com wrote:
I just publish a new version of PEP-604 with only the __or__ operator.
I thinks, now, it's can be accepted. What is the next step ?
Philippe
I'd recommend first re-posting your PEP, full text, as a brand new thread (altered subject, and not a reply to anything in this thread). Invite a second round of discussion. There'll be more bikeshedding to come, I'm confident of that :)
ChrisA

Not all types fit in a type annotation context. Due to Python's eager resolution of logical "or"s and "and"s, using this syntax is out of the question. The binary or is cute though.
- Ł
On 20 Sep 2019, at 15:34, Sebastian Rittau srittau@rittau.biz wrote:
Am 20.09.19 um 14:49 schrieb Chris Angelico:
Both "int or str" and "str?" have the problem that they don't work under existing Python syntax, so they would be far greater changes. The definition of the "or" operator is baked into the language, but the "|" operator can have its semantics defined by the objects on either side.
"or" works with "from __future__ import annotations", which is a fine limitation in my opinion.
- Sebastian
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/

Using binary negation to mean something other than negation bothers me. Using binary or seems useful and intuitive given precedence from at least Typescript.
I believe "x | None" is already an improvement over the status quo. I would suggest to focus on getting the Union shorthand stabilized and defer the decision over Optional.
On September 20, 2019 11:19:06 AM GMT+02:00, Philippe Prados philippe.prados@gmail.com wrote:
Hello everybody,
I just publish the PEP-0604 https://www.python.org/dev/peps/pep-0604/ for discussions (https://www.python.org/dev/peps/pep-0604/).
Scala 3 propose a new syntax for Union type. See here https://dotty.epfl.ch/docs/reference/new-types/union-types.html. I propose to add a similar syntax in Python.
# Operator for Union assert( int | str == Union[int,str]) assert( int | str | float == Union[int,str,float]) # Operator for Optional assert( ~int == Optional[int])
Now, it's possible to write:
def fn(bag:List[int | str], option: ~int = None) -> float | str: ...
in place of
def fn(bag:List[Option[int,str]], option: Optional[int] = None) -> Union[float,str]: ...
The discussion on python-new@python.org here https://mail.python.org/archives/list/python-ideas@python.org/thread/FCTXGDT2NNKRJQ6CDEPWUXHVG2AAQZZY/ have emerged the idea of extending also issubclass() and isinstance().
isinstance(int, int | str)
I think these syntaxes are more clear, and can help with the adoption of typing.
I test and implement these ideas in a two fork : One for CPython https://github.com/pprados/cpython/tree/updage_isinstance and one for MyPy https://github.com/pprados/mypy/tree/add_INVERT_to_types. See the branches add_OR_to_types (for Union syntax), add_INVERT_to_types (for Union and Optional syntax) or updage_isinstance (for new isinstance() and issubclass()).
How I implement that ? I add the operators __or__ and __revert__ to PyType_Type. The C code is similar of :
from typing import * def type_or(self,right): return Union[self,right] type(type).__or__ = type_or
with some check before return Union.
Actually, the accepted BNF syntax for typing is :
annotation: name_type name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
I propose to extend the BNF syntax to :
annotation: ( name_type | or_type | invert_type ) name_type: NAME (args)? args: '[' paramslist ']' paramslist: annotation (',' annotation)* [',']
or_type: name_type '|' annotation
invert_type: '~' annotation
Your remarks are welcome. Philippe Prados
participants (10)
-
Anthony Sottile
-
Bernat Gabor
-
Chris Angelico
-
Guido van Rossum
-
Ivan Levkivskyi
-
Jakub Stasiak
-
Markus Unterwaditzer
-
Philippe Prados
-
Sebastian Rittau
-
Łukasz Langa