On Sep 2, 2019, at 23:50, Philippe Prados <python@prados.fr> wrote:

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


Hold on. Are you proposing `Union[t1 | t2]` as a new spelling for `Union[t1, t2]`? That seems pointless. I thought you were proposing just `t1 | t2`, which seems a whole lot more useful (and no more disruptive)?

I’m going to assume this is just a typo?

Also, as far as the runtime-vs.-static, etc., issues of `int|str` vs. `(int,str)` vs. `{int,str}`, I think it’s worth getting them all down in one place.

 * `(int, str)`
   * Not just valid syntax, but a legal value in every version of Python, so you can use it in annotations and still run your code in 3.5 or something (you can’t type-check it as 3.5 code, but that rarely matters).
   * The same value can be passed to `isinstance` and will work as intended in every version of Python, unlike `Union[int, str]`, which fails because `Union` (like all generic types) refuses to allow its instantiated types in `isinstance`. Whether this is a good or bad thing is an open question, but it seems good at first glance.
   * Potentially confusing, implying `Tuple` rather than `Union`, but maybe that’s just something for people to get used to

 * `{int, str}`
   * Also a legal value in all existing Pythons. 
   * Not a legal argument to `isinstance`. Or `except` statements. This could be changed very easily and without much disruption, although of course only for 3.9+. It also opens the question of whether other Spam-or-tuple-of-Spam functions (like all the str methods) should also change to also accept -or-set-of-Spam, but Guido suggested that this could be left open until people either do or do not file bug reports about trying to pass a frozenset of suffixes to endswith.
   * Not confusing; it’s hard to imagine what it could mean other than “must be one of this set of types”.

 * `int|str`
   * Valid syntax in 3.8, but raises a TypeError when evaluated, so it can’t even be used in annotations without quoting it.
   * Can add `type.__or__` and `__ror__` methods in 3.9, so it _can_ be used unquoted, and can be inspected as a meaningful value at runtime. That means code they used it won’t compile in 3.8, but that’s nothing unprecedented, and might be worth it. And it’s not that major of a change.
   * Can’t be passed to `isinstance`. This would require an entirely independent change (which might be a good one, but should probably be argued out separately) to special-case `Union` as not like other generic types, and usable in `isinstance` calls.
   * Unlike the other options, this one has an obvious extension to `Optional` via a unary operator like `~`. 
   * Close enough to similar meanings in other languages that it would be an aid to memory rather than a source of confusion. Plus, even if you don’t know any of those other languages, and don’t know much about typing, and read it as “int or string”, you still get the right idea.