[PEP 604] Clarify interaction with ForwardRef, and None

Hi list! I was asked to bring this up here. When PEP604 was first introduced last year I noticed a few under-specified parts, namely how it interacts with ForwardRef and the edge case of `None | None` eg:
from typing import Union Union[int, 'str']
typing.Union[int, ForwardRef('str')]
int | 'str'
# should this raise an error, or return the same as above?
Union[None, "ref1"]
typing.Optional[ForwardRef('ref1')]
None | "ref1"
# should this construct (None first) be forbidden, or does str.__or__ or NoneType.__or__ need to be implemented?
Union[None, None]
<class 'NoneType'>
None | None
# should be forbidden? It seems very unlikely to come up in practise even if typing.Union supports it
Union["ref1","ref2"]
typing.Union[ForwardRef('ref1'), ForwardRef('ref2')]
"ref1" | "ref2"
# would this be str.__or__ returning types.Union?
In the discussion last year, it was suggested that there could be a `typing.Forward` that could be used instead of the bare string "ref" cases, or even requiring the union to be fully quoted eg `T = "Ref | OtherRef"`.

Thanks for bringing this up!
By the time PEP 604 goes live, the final aspect of PEP 563 will also go live: the behavior known as `from __future__ import annotations` will be the default.
This means that forward references are only needed rarely (and in some cases for backwards compatibility).
So I think it's fine if we don't allow ` int | 'str' `, requiring this to be written instead as ` 'int | str' `. We certainly can't allow ` 'int' | 'str' `.
Regarding `None | None`, I think that also shouldn't be allowed -- at least one of the arguments should be a type (or another union, or a generic alias like `list[int]`).
I think we will need to add these decisions explicitly to the PEP. Philippe or Maggie, can you propose a way to do this?
--Guido
On Wed, Jul 29, 2020 at 2:04 PM Richard Eames github@naddiseo.ca wrote:
Hi list! I was asked to bring this up here. When PEP604 was first introduced last year I noticed a few under-specified parts, namely how it interacts with ForwardRef and the edge case of `None | None` eg:
from typing import Union Union[int, 'str']
typing.Union[int, ForwardRef('str')]
int | 'str'
# should this raise an error, or return the same as above?
Union[None, "ref1"]
typing.Optional[ForwardRef('ref1')]
None | "ref1"
# should this construct (None first) be forbidden, or does str.__or__ or NoneType.__or__ need to be implemented?
Union[None, None]
<class 'NoneType'>
None | None
# should be forbidden? It seems very unlikely to come up in practise even if typing.Union supports it
Union["ref1","ref2"]
typing.Union[ForwardRef('ref1'), ForwardRef('ref2')]
"ref1" | "ref2"
# would this be str.__or__ returning types.Union?
In the discussion last year, it was suggested that there could be a `typing.Forward` that could be used instead of the bare string "ref" cases, or even requiring the union to be fully quoted eg `T = "Ref | OtherRef"`. _______________________________________________ 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/ Member address: guido@python.org
participants (2)
-
Guido van Rossum
-
Richard Eames