Steven already answered many of these, so I’ll just snip the ones he didn’t.

On Sep 19, 2019, at 00:03, Philippe Prados <philippe.pra...@gmail.com> wrote:
> 
> 
>  * The static types in typing are not instances of type, so you need to work 
> out what to do with them.
> I do not understand the remark. My patch of 'mypy' accept this new syntax.

If you’re only adding __or__ to type, then List[int] | Tuple[int] is still an 
exception.

>  * Making isinstance work isn’t a matter of accepting new syntax as you 
> suggest, but making the values already created by the existing syntax 
> work—and, since this appear to have been deliberated removed in 3.6, you need 
> to explain why this was a mistake and should be undone. (Have you uncovered 
> the reason for this change?) And whether it should affect just Union or other 
> types.
> Where I can find the argument to explain why this have been deliberated 
> removed in 3.6 ?
> In my implementation, they affect just Union. isinstance() can now accept 
> type, Tuple or Union.

If isinstahce(2, List) is still a TypeError, then what happens with 
isinstance(2, List|Tuple)? Probably it should raise a TypeError complaining 
that List can’t be used in type checks, like isinstance(2, List) does?

>  * What about except clauses? Shouldn’t they take unions if isinstance does? 
> How does that work?
> Good question. To accept `except TypeError | ZeroDivisionError:` in place of 
> `except (TypeError, ZeroDivisionError):`, the impact is bigger, but why not ?

As Steven pointed out, the syntax will already handle this, but you do need to 
change the implementation of how exceptions check for a matching except spec 
while looking for a handler. I’m guessing it’ll be easy, but I haven’t looked 
at that code in a long time.

>  * Should you be able to test whether List or List[int] is a subclass if 
> List|Tuple or List[int]|Tuple[int]? If so, that reverses even more of the 3.6 
> change, and then you have to explain why you can’t use issubclass(List[int], 
> Iterable[int]) or issubclass(List[Integral], List[int]) but can use this. If 
> not, what’s the use case for issubclass with unions in the first place?
> It's a question for "typing". My proposition change nothing about that.

No, typing avoids having to make this decision, because these aren’t types, and 
can’t be used in issubclass at all. If you’re changing that some these are now 
legal calls, you have to decide which ones, and what those calls return.

>  * You will probably want to create a new builtin type for unions, rather 
> than having a bunch of different parts of the Python core import from typing.
> May be.
> 
> 
>  * In addition to other benefits, someone (Stephen?) pointed out that builtin 
> support could mean that, e.g., isinstance(3, int|str) could be just as 
> efficient as isinstance(3, (int,str)), which alleviated multiple people’s 
> concerns. Is that’s part of the proposal you should make that point; if not, 
> explain why not.
> The implementation use the tuple present in the Union type. The impact is 
> just to check the type of the second parameter and replace it with the tuple 
> from the Union.

If you have to do an instance check against a type with a subclass hook, and 
that you have to import first, on every call to find out whether the second 
parameter is a Union, that will slow down every isinstance call. And if you 
then have to get the tuple out of the instance dict, that could make unions 
significantly slower than tuples.

Checking a value against a built in type and accessing a member out of a C 
struct are a lot faster

It’s possible that neither of those will affect performance enough to matter, 
but you’d have to benchmark it to prove that.

>  * Mentioning the wide variety of other languages’ typing systems that use | 
> for related features would probably make it more compelling.
> I find only Scala now.

The way you build sum types in ML and most languages derived or inspired by it 
(from Haskell to Swift) is with the | operator.

Most of those languages sum types give optional or mandatory constructor names 
to the alternatives, so it’s not quite the same thing as anonymous unions:

    IntStr = Int int | Str str

… this is a type whose values are an int or a str, but the way you construct 
one is with Int(2) or Str("a"), not with IntStr(2). And the way you extract the 
values is not by explicitly type-checking, but by pattern matching using | 
again, against the constructor names, something like this Int(n): Int(n*2) | 
Str(s): Str(f"{s} doubled")

For a more anonymous union, you usually use an explicit union or either or 
similar type: Either[int, str] gives you a type whose values are either an int 
or a str, and you access them with the Left and Right constructors from Either 
rather than specific named ones.

They could have syntactic sugar so that int|str means Either[int, str], it just 
doesn’t come up often enough—except the special case of Either[Error, X], which 
in some languages is the main way to do error handling. So if they do add any 
sugar, it’s usually for that special case, not the general one.

So you can see how this is all related to anonymous union types but not 
identical.

Scala is the exception here, but that’s because Scala has anonymous Union and 
Either as separate types, where Union means least upper bound on the lattice 
while Either is the direct one-or-the-other-and-nothing-else like Python’s 
Union. (And it’s the former rather than the latter that gets | for shorthand.(

The similarity is a lot like Python’s implicit Optional vs. the explicit 
Optional in other languages, where you construct an Optional[int] as a 
constructor call to Nothing() or Just(3) and then extract the value with 
pattern matching. Most of these languages have added a variety of kinds of 
syntactic sugar because it’s so common, so, e.g., something like x? means 
Optional[x], and ?x gives you a bool that says whether x is a non-empty value 
and !x means a pattern match on Just(x) and throw if it fails, and if let val = 
x: stuff is further shorthand for if ?x: val = !x; stuff and so on. None of 
this is identical to proposing ~int to mean Optional[int], but it’s all clearly 
similar, and shows how many languages have found it worth having shorthand like 
this.

So it’s the same with |. No language does something identical to what you’re 
proposing, but lots of languages do something similar and related.

One more thing:

>> In fact, having the two versions both ready could help clarify the 
>> discussion about PEP 585, and more generally about the advantages and 
>> disadvantages of going more toward a “two-kinded” type system vs. leaning 
>> more into “everything is first-class”.

I don’t think this was very clear, so apologies.

In lots of languages (Scala, Haskell, Swift, even C++) there’s syntax for 
operating on types, but it’s separate from the syntax for operating on values. 
PEP 585 is a step in that direction—the syntax of annotations is still the 
syntax of expressions, but the semantics are different (they just aren’t fully 
evaluated at all). That means you can put forward references in an annotation 
without getting a NameError. And it means you could define int|str as valid in 
annotations, without making it valid at runtime. This would avoid all the hard 
decisions and optimization issues, and it would be a lot closer to what Scala 
does, and it could even open the door for things like using the | operator for 
related but different meanings in type expressions and value expressions (e.g., 
the way ? means Optional in a type expression but optional-chaining in a value 
expression in Swift).

On the other hand, in Python, everything is a first-class value, including 
types, and everything that types do (constructing objects, type checks, even 
metaclass stuff) is determined by the normal language syntax and semantics 
operating on types as values. There are a lot of benefits to that. Which is 
probably why everyone who uses Python naturally expects that if int|str is a 
thing, it’ll be a thing you can pass around at runtime and use in isinstance 
and so on, even if that makes the language and the implementation a little more 
complicated and they don’t have a compelling use in mind for it.

I haven’t followed the discussion around PEP 585, but I suspect that when you 
take this PEP to the typing-sig people, these questions are going to be more 
relevant to them than the bikeshedding stuff about how to spell ~ and how other 
languages spell it. But I could be wrong.
_______________________________________________
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/IE5RAMFOASPN4THBNDXM3FBXSD7KKKBA/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to