On Jun 17, 2019, at 07:47, Guido van Rossum <guido@python.org> wrote:

On Mon, Jun 17, 2019 at 7:23 AM Rhodri James <rhodri@kynesim.co.uk> wrote:
On 16/06/2019 03:34, Guido van Rossum wrote:
> I don't actually know how viable this proposal is, but given that it's
> being debated at some length, I'd like to put in my  opinion that *if*
> we're going to define an operator that's (roughly) synonymous with
> issubclass(), it should be '<:', which is used in other languages (e.g.
> Scala) and notational systems (https://en.wikipedia.org/wiki/Subtyping).
> Overloading '<=' would be easier to implement, but would also cause enough
> confusion that I think we should avoid it at all cost.

I rather strongly disagree.  We are describing a fairly standard
incomplete ordering, which makes the comparison operators completely
appropriate.  Adding new syntax for something that doesn't need it is
the thing likely to cause confusion.

Indeed it would work the same way as set comparison does, if you interpret a type as the set of its instances.

But I imagine that many Python users are not so familiar with this abstraction level (even if they use isinstance() and issubclass() all day long). Sometimes using a *different* operator is helpful to send a signal to the reader that a *different* kind of thing is being manipulated -- sort of like how you can tell that a collection is a list or a set by noticing whether values are added using append() or add().

Type theorists apparently have chosen to use the <: notation, and presumably for the same reason.

Theoretical, and Scala (and Haskell, C++, etc.), types are a different kind of thing from objects, meta-objects that can only be used in special meta-level computation, so using a different operator makes sense. It’s like using |- rather than -> in proofs in basic logic.

Python makes types first-class objects, and then uses normal value-level computation for everything. Conceptually, there’s no good reason not to extend that uniform syntax to uniform operators.

In short, the key is that isinstance(type, type) is not even well-formed in type theory, but in Python, it’s guaranteed true.[1]

Sure, most people who want to write type-computation expressions often enough that they need operators, and who are familiar with the abstraction of types as sets, will be people who are familiar with type theory or Scala or Rank-N Haskell or whatever, and are likely to be more comfortable with <: syntax. And there’s already some special syntax for type-level computation (the class statement), so it’s not like it would be unprecedented. But most such people will also be sophisticated enough to avoid confusion when using <. And to write their own metaclass that defines __lt__ if they need it (or at least fetch one from PyPI and use it). Also. I think we’re talking about something only a smallish number of people will ever want to do, and then only pretty rarely, in the first place.

So I don’t think anything needs to be changed at all.

[1] Technically, this means Python’s type type isn’t a typed set, or even a well-founded set. This raises all kinds of interesting complications; someone could probably write a whole thesis on how to integrate anti-foundation and types. But practically, when programming in Python, it makes a lot of things simpler to think about, and the confusion almost never comes up and isn’t that hard to deal with when it does. It goes along with, e.g., types being their own constructor functions. And if lists can contain themselves, and so can sets (you have to subclass set or frozenset, but the result is a perfectly valid subtype), why not types?