Guido van Rossum wrote:
> 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).
You are probably right, it's all a matter of how used our brains are to seeing stuff. So if I started using it more frequently, after some time I would probably appreciate it over `Union[T, None]`.
> > 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?
I don't miss the `-` in the context because my brain is trained on recognizing such patterns. We encounter negative numbers everywhere, from (pre-)school on, so this pattern is easy to recognize. However `~Noun` is not something you've likely seen in the real world (or anywhere), so it's much harder to recognize. I cn wrt ths txt wtht vwls or eevn rdoerer teh lterets and you'll still be able to read it because your brain just fills in what it expects (i.e. what it is accustomed to). For that reason `~Node` is much harder to recognize than `-3637` because I wouldn't expect a `~` to appear in that place.
> 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. :-)
I don't think it's unfortunate, it's pretty neat syntax (and intuitive). Checking if `x` is an instance of `y` it makes sense to "list" (`tuple`) multiple options for `y`. It's a clever way of reusing the available syntax / functionality of the language. And I think this is what typing should do as well: build around the existing language and use whatever is available. Adding `__or__` to `type` for allowing things like `int | str` on the other hand bends the language toward typing and thus is a step in the opposite direction.
Then I don't think it's the comma that receives emphasis in the syntax `(int, str)`, it's rather the parens - and those, as a bonus, provide visual boundaries for the beginning and end of the union. Consider
def foo(x: str | int, y: list):
versus
def foo(x: (str, int), y: list):
The comma is a small character, visually the scene will be dominated by the matching parens - and whatever is inside is anyway a common sight as we are used to seeing tuples. Hence I think from readability perspective it's a plus to reuse existing, common syntax.
I agree that there is the ambiguity with `(int, str)` being interpreted as `Tuple[int, str]` and this is a valid argument. Since I've used the `isinstance(x, (y,z))` syntax quite often I wouldn't interpret `(int, str)` as a tuple but of course for other people the situation might be completely different. Hence that could really be a blocker.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@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/ZONQON7O46YC666CGBBZ3XDX7SBWITOU/
Code of Conduct: http://python.org/psf/codeofconduct/