On Thu, Aug 29, 2019 at 4:04 PM Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
I never really understood the importance of `Optional`. Often it can be left out altogether and in other cases I find `Union[T, None]` more expressive (explicit) than `Optional[T]` (+ the latter saves only 3 chars).

I respectfully disagree. In our (huge) codebase we see way more occurrences of Optional than of Union. It's not that it saves a tremendous amount of typing -- it's a much more intuitive meaning. Every time I see Union[T, None] I have to read it carefully to see what it means. When I see Optional[T] my brain moves on immediately (in a sense it's only one bit of information).
 
Especially for people not familiar with typing, the meaning of `Optional` is not obvious at first sight. `Union[T, None]` on the other hand is pretty clear. Also in other cases, where the default (fallback) is different from `None`, you'd have to use `Union` anyway. For example a function that normally returns an object of type `T` but in some circumstances it cannot and then it returns the reason as a `str`, i.e. `-> Union[T, str]`; `Optional` won't help here. Scanning through the docs and PEP I can't find strongly motivating examples for `Optional` (over `Union[T, None]`). E.g. in the following:

    def lookup(self, name: str) -> Optional[Node]:
        nodes = self.get(name)
        if nodes:
            return nodes[-1]
        return None

I would rather write `Union[Node, None]` because that's much more explicit about what happens.

Then introducing `~T` in place of `Optional[T]` just further obfuscates the meaning of the code:

    def lookup(self, name: str) -> ~Node:

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

Do you easily miss the `-` in an expression like `-2`?

Surely the meaning of `?` in a programming language also has to be learned. And not every language uses it to mean "optional" (IIRC there's a language where it means "boolean" -- maybe Scheme?)
 
For `Union` on the other hand it would be more helpful to have a shorter syntax, `int | str` seems pretty clear, but what prevents tuples `(int, str)` from being interpreted as unions by type checkers. This doesn't require any changes to the built-in types and it is aligned with the already existing syntax for checking multiple types with `isinstance` or `issubclass`: `isinstance(x, (int, str))`. Having used this a couple of times, whenever I see a tuple of types I immediately think of them as `or` options.

First, *if* we were to introduce `(int, str)` it would make more sense for it to mean `Tuple[int, str]` (tuples are also a very common type). Second, comma is already very overloaded.

Yes, it's unfortunately that `(int, str)` means "union" in `isinstance()` but it's not enough to sway me.

Anyway, let's just paint the bikeshed *some* color. :-)

--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him/his (why is my pronoun here?)