Hello,

I propose to resume all the arguments (I add my remarks in italic) and
major questions.

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:
   https://github.com/python/typing/issues/387
   -

      It is maybe too late to change this, many people are already get used
      to current notation.
      -

         I 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)
      -

         I do it
         -

      There are currently no volunteer to implement this in mypy
      -

         I implement this (One patch for CPython
         <https://github.com/pprados/cpython> and one for MyPy
         <https://github.com/pprados/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
   <https://dotty.epfl.ch/docs/reference/new-types/union-types.html>
   -

   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: 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.
   -

      My patch of mypy is just 20 lines of codes

If yes,

   -

   Change only the PEP484 <https://www.python.org/dev/peps/pep-0484/> (Type
   hints) to accept the syntax `type1 | type2` ?
   -

      PRO: The PEP563 <https://www.python.org/dev/peps/pep-0563/>
      (Postponed Evaluation of Annotations) is enough to accept this proposition
      -

         CONS: 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'

   -

   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.

Add a new operator for `Optional[type]` ?

   -

   CONS: `foo | None` is short and readable
   -

   CONS: `foo | None` it's 3 fewer characters than `Optional[foo]`, or 30
   fewer if you include the full removal of `from typing import Optional`.
   the additional gain of `~foo` is only 6 characters.
   -

   PRO: help the readability, with a lot of parameters:

def f(source: str | None, destination: str | None, param: int | None):...
def f(source: ~str, destination: ~str, param: ~int):...

   -

   PRO: I'm currently working on annotating a very large codebase, and
   `Optional[T]` is so frequent that I think `T | None` would not be enough
   of an improvement.
   -

   PRO: Adding a default `__or__` overload to `type` seems a reasonable
   price to pay in 3.9, and ditto for `__invert__`. Type checkers can
   support this in older Python versions using PEP 563 or in type comments or
   in "forward references" (types hidden in string literals).
   -

   CONS: The `~` is easy to be missed (at least by human readers) and the
   meaning not obvious.
   -

   PRO: Also, Python’s typing system is a lot easier to grasp if you’re
   familiar with an established modern-typed language (Swift, Scala, Haskell,
   F#, etc.), and they also use `Optional[T]` (or `optional<T>` or `Maybe t`
   or some other spelling of the same idea) all over be place—so often that
   many of them have added shortcuts like `T?` to make it easier to write
   and less intrusive to read.

if yes,

Add operator `__revert__` in type type to use syntax like `~int` ?

   -

   CONS: `~` is not automatically readable
   -

      like `:` to separate variable and typing.
      -

   CONS: `~` means complement, which is a completely different thing from
   `|None`. `~int` seems like it would actually harm comprehension instead
   of helping.
   -

   PRO: the slight abuse of `~int` meaning "maybe int" is pretty plausible
   (consider how "approximately equal" is written mathematically).
   -

   PRO: Possibly relevant for tilde:
   
https://www.thecut.com/article/why-the-internet-tilde-is-our-most-perfect-tool-for-snark.html

   -

   CONS: With `~` there probably won't be a confusion in that sense, but
   someone reading it for the first time will definitely need to look it up
   (which is fine i.m.o.).
   -

      Like the first time someone reading the annotation

def f(a=int):...
def f(a:int):...

Add operator __add__ in type type to use syntax like +int ?

   -

   PRO: `+foo` definitely seems to say "foo, plus something else" to me
   much more than `~foo`.
   -

   CON: `+foo` is less intuitive than `~foo` for `Optional`

Like Kotlin <https://kotlinlang.org/docs/reference/null-safety.html>, add a
new `?` operator to use syntax like `int?` ou `?int` ?

   -

   CONS: It’s not compatible with IPython and Jupyter Lab `?smth` displays
   help for symbol `smth`
   -

   CONS: With default arguments, `?=` looks... not great
   -

   def f(source: str?=def_src, destination: str?=MISSING, param: int?=1):
   ...

Extend `isinstance()` and `issubclass()` to accept `Union` ?

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":

Do nothing, open a new PEP or extend PEP585 ?

   -

   I do think we should probably review PEP 585
   <https://www.python.org/dev/peps/pep-0585/> before doing anything about
   unions specifically -- likely there are bigger fish to fry
   -

   PEP 585 has not received much discussion


So, I think it’s time to answer these questions:

   -

   Add a new operator for `Union[type1|type2]` ?
   -

   If yes
   -

      Change only the PEP484 (Type hints) to accept the syntax `type1 |
      type2` ?
      -

      Use `(int, str)` in place of `Union[int,str]` ?
      -

      Use `{int, str]` in place of `Union[int,str]` ?
      -

   Add a new operator for `Optional[type]` ?
   -

   If yes,
   -

      Add operator `__revert__` in type type to use syntax like `~int` ?
      -

      Add operator `__add__` in type type to use syntax like +int ?
      -

   Extend `isinstance()` and `issubclass()` to accept `Union` ?

Do nothing, open a new PEP
<https://github.com/pprados/peps/blob/master/pep-9999.rst> or extend PEP585
<https://www.python.org/dev/peps/pep-0585/> ?

Philippe

Le mar. 3 sept. 2019 à 08:30, Philippe Prados <pyt...@prados.fr> a écrit :

> With my implementation, I can check
> assert int | None == None | int
> is true
>
> Le lun. 2 sept. 2019 à 13:32, Ivan Levkivskyi <levkivs...@gmail.com> a
> écrit :
>
>> On Thu, 29 Aug 2019 at 23:48, Guido van Rossum <gu...@python.org> wrote:
>>
>>> On Thu, Aug 29, 2019 at 3:33 PM Chris Angelico <ros...@gmail.com> wrote:
>>>
>>>> On Fri, Aug 30, 2019 at 8:28 AM Guido van Rossum <gu...@python.org>
>>>> wrote:
>>>
>>> [...]
>>>
>>>
>>> I do tink we should probably review PEP 585 before doing anything about
>>> unions specifically -- likely there are bigger fish to fry. (And PEP 585
>>> has not received much discussion.)
>>>
>>
>> I also agree with this. Generally I am fine with Union[int, str] and
>> Optional[int], but I also see how some people might want a shorter
>> notation. Many things around typing have been previously
>> rejected because we didn't want to introduce any (or at least minimal)
>> changes to the syntax and runtime, but now that typing is much more widely
>> used we can reconsider some of these.
>> Importantly, I think this should be done in a systematic way (potentially
>> using PEP 585 draft as a starting point).
>>
>> --
>> Ivan
>>
>> _______________________________________________
>> Python-ideas mailing list -- python-ideas@python.org
>> To unsubscribe send an email to python-ideas-le...@python.org
>> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>> Message archived at
>> https://mail.python.org/archives/list/python-ideas@python.org/message/YZHAERD5T4TZL62A6EI4BCKKAQYNJGSU/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/SAHJWREC7ESRH3WTDITRM2JSI3OUMPFM/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to