On Oct 13, 2019, at 18:39, Steven D'Aprano <st...@pearwood.info> wrote: > > Even when the class can be identified as equivalent to > its set of values, such as for numeric types, there are all sorts of > complexities that will only lead to confusion: > > from numbers import Real > 1.0 in Real # okay, unproblematic > 2+3j in complex # also okay > 1 in complex # mathematically true, but isinstance-wise false > float('INF') in Real # isinstance-wise true, but mathematically false.
I agree with your conclusion, but I think this is the wrong way to argue it. `1 in complex` is _not_ mathematically true. Simplifying a bit, the elements of the algebra of complex numbers are ordered pairs of real numbers, and `1` is not a pair. When you’re working in, say, complex analysis, you just assume the usual morphism that maps every real to a unique complex (and some complexes to a unique real), and you can loosely multiply a real by a complex and so on. But when you’re working on the actual algebras or the sets/types beneath them, you can’t do that. `R` is not a subset of `C`, and `1 in C` is just not true. In other words, the distinction in Python—that 1 and 1+0j are in some sense “the same number” but in another sense not even the same type of number—is exactly the same as in math; you don’t need anything extra to justify it. As for infinity: the problem there is that the algebra of IEEE floats just isn’t the same thing as the real algebra (and in fact it’s closer to rationals than to reals). By pretending otherwise, Python has already bitten that bullet. And if the type you want to call `Real` does include IEEE floats, then mathematically it does include `inf`. Finally, it’s not just numeric types, but all types that are identifiable as the set of their values (plus possibly some additional structure). The fact that there are a potentially infinite number of `Dog` instances doesn’t mean they don’t form a set, or that `fido` isn’t a member of that set; `N` (and, in fact, Python `int`) is just as infinite, and `R` is just as non-denumerable. All that being said, it isn’t _useful_ to treat Python types as pure type-theory constructs. They make for a good analogy, and a good grounding to argue for changes to Python’s type system, but they’re not the same thing. What `isinstance` means is not inclusion in a set, or at least not one that can be expressed even in an approximate way in Python. Python allows for subclasses that aren’t subtypes, and instance checking that approximates structural subtypes, and even explicitly lying to the type system for good practical reasons, and all of that is what `isinstance` means. And that’s not confusing in practice, but using `in` to mean the same thing would be. Also, from a practical point of view, why do we need another way to spell the isa relationship when we already have a perfectly good—and more flexible (e.g., surely `spam in (Eggs, Cheese)` wouldn’t mean the same thing as `isinstance(spam, (Eggs, Cheese))`)—way to do it. TOOWTDI isn’t an iron-clad rule, but this is about as close to a paradigm case where it should apply as you’re ever going to see. Finally, in languages that care a lot more about this kind of thing (like Haskell, or Scala), either types aren’t first-class objects at all, or they’re first-class objects into a two-kinded system; they’re definitely not sets at the language level. So why should Python try to go farther than any of them? _______________________________________________ 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/SAD3LN3XGO5NCOZ6OQWFVTICFDVYF5E2/ Code of Conduct: http://python.org/psf/codeofconduct/