Comparison operator support (>= and <=) for type
Let's assume you have this model: ``` class Base: pass class A(Base): pass class B(Base): pass class C(A): pass ``` While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)` Because, since == means equality check. With the same logic, a class wraps another class is actually greater than this class from its type.
On Fri, Jun 14, 2019 at 08:02:15AM -0000, eminbugrasaral--- via Python-ideas wrote:
class Base: pass
class A(Base): pass [...]
While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)`
On the one hand... 1. I do this *a lot* when describing classes. I might say something like "suppose we have classes A > B > C > D" and I've not yet come across anyone who doesn't understand what I mean by that. So from that perspective, I think that enabling > >= < <= as operators which work on classes themselves is a simple and obvious syntactic shortcut for variations of issubclass(). 2. In its favour, there's no obvious way to test "is a superclass" without reversing the logic: # test that A is a SUPERclass of B: assert issubclass(B, A) # SUBclass !!! and no simple way to talk about *strict* subclass and superclass relationships without a verbose compound test: assert issubclass(parent, child) and child != parent But on the other hand: I can't remember the last time I needed to do an issubclass test. If I've done more than four or five in the last decade, I'd be surprised. So I am not convinced that this is common enough to deserve syntactic sugar. I'd like to hear what people who do a lot of subclass testing think. But for myself, I don't oppose this, but I'm only every-so-slightly in favour. One possible objection which I don't think is a good objection is that class relationships don't form a trichotomy: given two class A and B, it is *not true* that one of these must hold: A == B *or* A > B *or* A < B Honestly, I don't think that really matters. That trichotomy doesn't even hold for floats, and it doesn't hold for sets, so I don't think this will be a problem. -- Steven
On Fri, Jun 14, 2019 at 12:39 PM Steven D'Aprano <steve@pearwood.info> wrote:
and no simple way to talk about *strict* subclass and superclass relationships without a verbose compound test:
assert issubclass(parent, child) and child != parent
Well, why not go further then and make the following thing to be a strict check? `Parent >> Child` Which is `True` when and only when `Child` is a direct subclass of `Parent`.
On 14 Jun 2019, at 11:31, Steven D'Aprano <steve@pearwood.info> wrote:
On Fri, Jun 14, 2019 at 08:02:15AM -0000, eminbugrasaral--- via Python-ideas wrote: class Base: pass
class A(Base): pass [...]
While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)`
I think this a bad idea. It's all down to statistics: - how many times will this feature hide an error (you had classes but wanted instances) - how often do you do this type of check Anecdotally I pretty much never use issubclass. But I do sometimes miss parents so I get a class when I wanted an instance. / Anders (replying to the wrong mail because my mail client doesn't permit me to reply all to the correct one for some reason)
I think the logic breaks down with multiple inheritance. If you make C(A, B), then you can say C > A and C > B, but then you can't say A > B or A < B which breaks sorting. If you want to know if a B inherits from Base, then I think `Base in B.mro()` will cover that just as succinctly. And if you need to know position you can compare indexes into the MRO. On Fri, Jun 14, 2019 at 1:06 AM eminbugrasaral--- via Python-ideas < python-ideas@python.org> wrote:
Let's assume you have this model:
``` class Base: pass
class A(Base): pass
class B(Base): pass
class C(A): pass ```
While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)`
Because, since == means equality check. With the same logic, a class wraps another class is actually greater than this class from its type. _______________________________________________ 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/6W7HCI... Code of Conduct: http://python.org/psf/codeofconduct/
And yet: This is trivial to implement in a custom metaclass - and maybe it would make default type too "noisy". I am -1 on this going into normal classes, and +0 for having a colaborative metaclass with __lt__, __eq__ and such implementing these on the stdlib. Maybe living in "types". On Fri, 14 Jun 2019 at 14:53, Brett Cannon <brett@python.org> wrote:
I think the logic breaks down with multiple inheritance. If you make C(A, B), then you can say C > A and C > B, but then you can't say A > B or A < B which breaks sorting.
If you want to know if a B inherits from Base, then I think `Base in B.mro()` will cover that just as succinctly. And if you need to know position you can compare indexes into the MRO.
On Fri, Jun 14, 2019 at 1:06 AM eminbugrasaral--- via Python-ideas < python-ideas@python.org> wrote:
Let's assume you have this model:
``` class Base: pass
class A(Base): pass
class B(Base): pass
class C(A): pass ```
While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)`
Because, since == means equality check. With the same logic, a class wraps another class is actually greater than this class from its type. _______________________________________________ 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/6W7HCI... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ 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/IFW2UQ... Code of Conduct: http://python.org/psf/codeofconduct/
Bad idea. issubclass() works well. Adding operator support should be considered very carefully. I prefer a good portion of conservatism for such changes. How often the proposed change is needed? It adds a new complexity (documenting, teaching etc) without real benefits for daily jobs. On Fri, Jun 14, 2019 at 9:42 PM Joao S. O. Bueno <jsbueno@python.org.br> wrote:
And yet:
This is trivial to implement in a custom metaclass - and maybe it would make default type too "noisy".
I am -1 on this going into normal classes, and +0 for having a colaborative metaclass with __lt__, __eq__ and such implementing these on the stdlib. Maybe living in "types".
On Fri, 14 Jun 2019 at 14:53, Brett Cannon <brett@python.org> wrote:
I think the logic breaks down with multiple inheritance. If you make C(A, B), then you can say C > A and C > B, but then you can't say A > B or A < B which breaks sorting.
If you want to know if a B inherits from Base, then I think `Base in B.mro()` will cover that just as succinctly. And if you need to know position you can compare indexes into the MRO.
On Fri, Jun 14, 2019 at 1:06 AM eminbugrasaral--- via Python-ideas <python-ideas@python.org> wrote:
Let's assume you have this model:
``` class Base: pass
class A(Base): pass
class B(Base): pass
class C(A): pass ```
While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)`
Because, since == means equality check. With the same logic, a class wraps another class is actually greater than this class from its type. _______________________________________________ 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/6W7HCI... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ 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/IFW2UQ... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ 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/UYNPZX... Code of Conduct: http://python.org/psf/codeofconduct/
-- Thanks, Andrew Svetlov
Most of the times, I am ending up using isinstance(A, list) or type(A) == list if I can. Therefore I feel like it’s not consistent. And isinstance itself has 10 characters in its name already. Would love to follow == like syntax which we allow to compare types. I think I have to check how __eq__ is implemented for object before deciding if it’s really inconsistent or not. If the __eq__ is checking over object.__base__ or something similar, then my proposition makes sense. I am not in favor of adding an unnecessary operator writing for base class if it’s not the case. Excuse me if I am talking without really grasping the idea of using == for type comparison. I will do more research.
On 14. Jun 2019, at 21:05, Andrew Svetlov <andrew.svetlov@gmail.com> wrote:
Bad idea. issubclass() works well. Adding operator support should be considered very carefully. I prefer a good portion of conservatism for such changes. How often the proposed change is needed? It adds a new complexity (documenting, teaching etc) without real benefits for daily jobs.
On Fri, Jun 14, 2019 at 9:42 PM Joao S. O. Bueno <jsbueno@python.org.br> wrote:
And yet:
This is trivial to implement in a custom metaclass - and maybe it would make default type too "noisy".
I am -1 on this going into normal classes, and +0 for having a colaborative metaclass with __lt__, __eq__ and such implementing these on the stdlib. Maybe living in "types".
On Fri, 14 Jun 2019 at 14:53, Brett Cannon <brett@python.org> wrote:
I think the logic breaks down with multiple inheritance. If you make C(A, B), then you can say C > A and C > B, but then you can't say A > B or A < B which breaks sorting.
If you want to know if a B inherits from Base, then I think `Base in B.mro()` will cover that just as succinctly. And if you need to know position you can compare indexes into the MRO.
On Fri, Jun 14, 2019 at 1:06 AM eminbugrasaral--- via Python-ideas <python-ideas@python.org> wrote:
Let's assume you have this model:
``` class Base: pass
class A(Base): pass
class B(Base): pass
class C(A): pass ```
While we can do `A == B`, or `B == C` or `B == B`, I would expect to be able to compare like this as well: `A >= B (if B is subclass or itself of A)`, or `B <= C (if B is a subclass or itself of C)`
Because, since == means equality check. With the same logic, a class wraps another class is actually greater than this class from its type. _______________________________________________ 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/6W7HCI... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ 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/IFW2UQ... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ 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/UYNPZX... Code of Conduct: http://python.org/psf/codeofconduct/
-- Thanks, Andrew Svetlov
On Fri, Jun 14, 2019 at 10:45:17AM -0700, Brett Cannon wrote:
I think the logic breaks down with multiple inheritance. If you make C(A, B), then you can say C > A and C > B, but then you can't say A > B or A < B which breaks sorting.
Just like sets, or floats, or anything other type that doesn't implement a total order. In practice, when was the last time you got bitten by the fact that sorting of sets or arbitrary floats is "broken"?
If you want to know if a B inherits from Base, then I think `Base in B.mro()` will cover that just as succinctly.
I wonder why we have issubclass when we can check the mro ourselves. Actually I've often wondered why we have both type.__mro__ and type.mro() and what the difference is. I don't think that "Base in B.mro()" (15 chars) is just as succinct as "Base >= B" (9 chars). And the strict parent check is worse: Base != B and Base in B.mro()" (29 chars) "Base > B" (8 chars, 6 if you leave out the spaces) It is hard to beat operators for succinctness. But I don't think the advantage of this is in minimizing the number of characters that need to be typed. I think the advantage is that people already think of parent/child class relationships in terms of > symbol representing superclass > subclass relationships. The big question in my mind is not whether this is good, useful, obvious syntax. I think it is. The question is whether it is good and useful *enough* to justify the feature. -- Steven
On Fri, Jun 14, 2019, 13:49 Brett Cannon <brett@python.org> wrote:
I think the logic breaks down with multiple inheritance. If you make C(A, B), then you can say C > A and C > B, but then you can't say A > B or A < B which breaks sorting.
The logic is fine. Classes can be considered as containers of their instances, and that logic is already used with Python's sets. You can even consider intersections and unions of classes (which are already used to express type constraints). That means you can define __contains__ and comparisons for classes, and the logic will be self-consistent. Mathematically, it's just set theory. Regular expression objects can also be considered as computed collections of the strings they match. You can even enumerate these collections. However, the proposed feature will reserve comparison and container operations to the classes-as-instance-containers concept. That means programmers can't use those operators for something else. If they do, their classes will not play nicely with any library that DOES use the feature, even if they themselves don't use the feature. I wonder how many codebases already use comparison and containment in their metaclasses, and how many use them for something OTHER than classes-as-instance-containers.
If you want to know if a B inherits from Base, then I think `Base in B.mro()` will cover that just as succinctly. And if you need to know position you can compare indexes into the MRO.
Using the MRO directly will ignore virtual subclassing. `issubclass` is the right equivalent. I can't imagine a reason to need to know relative positions in the MRO, except in debugging attribute resolution.
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. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
On Sat, Jun 15, 2019 at 10:26 PM Guido van Rossum <guido@python.org> 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.
Note that making new operators means class containment relationships can't be used as normal comparisons, such as for `sort`, especially of nested comparables such as tuples of classes. I'm not sure how to define a sort key that works even for a simple list of classes, other than to create a wrapper which implements class comparisons. I don't think the proposal is viable. It might have been viable if one of these conditions were true: 1. A lot more programmers learned, from the start, to think of types as collections of their instances. Then the consistency would pay off, by reducing mental load for those programmers. 2. There were more libraries/features that used comparison operators AND there was a reason for classes to ducktype into those libraries. 3. Subclass checking often happened within complex boolean algebra. The succinctness of operators would then help readability. For simple boolean algebra, issubclass and isinstance can take tuples of classes: issubclass(C, (A, B)) # Checks if C is a subclass of A OR B.
On 6/16/19 7:49 AM, Franklin? Lee wrote:
On Sat, Jun 15, 2019 at 10:26 PM Guido van Rossum <guido@python.org> 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 don't think the proposal is viable. It might have been viable if one of these conditions were true:
1. A lot more programmers learned, from the start, to think of types as collections of their instances. Then the consistency would pay off, by reducing mental load for those programmers.
Disclaimer: I am *not* an expert on types and typing systems. That said: How would I "think of types as collections of their instances"? For example, in what sense is the type list a collection of instances of lists? Or the type int a collection of instances of integers? In my mind, a type is a description/container/shortand for a collection of properties or behaviors of instances of that type. For example, I'd much rather know that I can access a specific element of a collection by index than know that the collection is a list, or that some object can present a message to the user rather than that object being an instance of some logging class. I think that duck typing is exactly what I just described: I can have a "file-like object" that behaves like a file, whether or not it represents an actual file in a filesystem. I learned, not quite from the start, but certainly early on, that what an object *does* (i.e., its properties and behaviors) is more important than what an object *is* (i.e., its type).
On Sun, Jun 16, 2019 at 8:58 AM Dan Sommers <2QdxY4RzWzUUiLuE@potatochowder.com> wrote:
On 6/16/19 7:49 AM, Franklin? Lee wrote:
On Sat, Jun 15, 2019 at 10:26 PM Guido van Rossum <guido@python.org> 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 don't think the proposal is viable. It might have been viable if one of these conditions were true:
1. A lot more programmers learned, from the start, to think of types as collections of their instances. Then the consistency would pay off, by reducing mental load for those programmers.
Disclaimer: I am *not* an expert on types and typing systems. That said:
How would I "think of types as collections of their instances"? For example, in what sense is the type list a collection of instances of lists? Or the type int a collection of instances of integers?
In my mind, a type is a description/container/shortand for a collection of properties or behaviors of instances of that type. For example, I'd much rather know that I can access a specific element of a collection by index than know that the collection is a list, or that some object can present a message to the user rather than that object being an instance of some logging class. I think that duck typing is exactly what I just described: I can have a "file-like object" that behaves like a file, whether or not it represents an actual file in a filesystem.
I learned, not quite from the start, but certainly early on, that what an object *does* (i.e., its properties and behaviors) is more important than what an object *is* (i.e., its type).
The proposed feature is for expressing type relations, which only matters when you care about types. The feature will only be useful when you care about types. The syntax will only help/hurt readability when the code cares about types.
On Sun, Jun 16, 2019 at 6:08 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
The proposed feature is for expressing type relations, which only matters when you care about types. The feature will only be useful when you care about types. The syntax will only help/hurt readability when the code cares about types.
And Python programmers rarely care about types -- that's why we use Python.d Much to my surprise, a lot more Python programmers are starting to care about static type checking, but that's, well, static, so also not relevant to this idea. I think we should be a bit careful about how we interpret discussion on this list -- I suspect that the amount of discussion is mostly about how interesting a topic is -- not how good an idea it is to actually include it in Python. -CHB
--
Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
On Sun, Jun 16, 2019 at 08:04:44AM -0700, Christopher Barker wrote:
On Sun, Jun 16, 2019 at 6:08 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
The proposed feature is for expressing type relations, which only matters when you care about types. The feature will only be useful when you care about types. The syntax will only help/hurt readability when the code cares about types.
And Python programmers rarely care about types -- that's why we use Python.d
I'm pretty sure that Python programmers *frequently* care about types. I know I do. How else do you avoid TypeErrors and AttributeErrors, if you don't care what type of data you're using? What they might not be doing is *explicitly* type-checking using isinstance or issubclass, but that doesn't mean they don't care about types. Whether we duck-type, or LBYL with an explicit test, or EAPF with a try...except block, or just rely on the caller never passing the wrong thing to our functions, we still care about types. -- Steven
On Sun, Jun 16, 2019 at 7:41 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sun, Jun 16, 2019 at 08:04:44AM -0700, Christopher Barker wrote:
On Sun, Jun 16, 2019 at 6:08 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
The proposed feature is for expressing type relations, which only matters when you care about types. The feature will only be useful when you care about types. The syntax will only help/hurt readability when the code cares about types.
And Python programmers rarely care about types -- that's why we use Python.d
I'm pretty sure that Python programmers *frequently* care about types. I know I do. How else do you avoid TypeErrors and AttributeErrors, if you don't care what type of data you're using?
What they might not be doing is *explicitly* type-checking using isinstance or issubclass, but that doesn't mean they don't care about types. Whether we duck-type, or LBYL with an explicit test, or EAPF with a try...except block, or just rely on the caller never passing the wrong thing to our functions, we still care about types.
I second on that, a lot of people who uses Python or Ruby, end up writing their own type system (which is a major reason why language like scala becomes more and more popular and its user base has a lot of former dynamic language users). This is especially true for library and framework developers, where you want to capture issues early, e.g. by forcing policies and make sure user defined class is deriving from a common base class and some magic happens behind the scene.
On 18/06/2019 11:06, Yanghao Hua wrote:
On Sun, Jun 16, 2019 at 7:41 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sun, Jun 16, 2019 at 08:04:44AM -0700, Christopher Barker wrote:
On Sun, Jun 16, 2019 at 6:08 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
The proposed feature is for expressing type relations, which only matters when you care about types. The feature will only be useful when you care about types. The syntax will only help/hurt readability when the code cares about types.
And Python programmers rarely care about types -- that's why we use Python.d
I'm pretty sure that Python programmers *frequently* care about types. I know I do. How else do you avoid TypeErrors and AttributeErrors, if you don't care what type of data you're using?
What they might not be doing is *explicitly* type-checking using isinstance or issubclass, but that doesn't mean they don't care about types. Whether we duck-type, or LBYL with an explicit test, or EAPF with a try...except block, or just rely on the caller never passing the wrong thing to our functions, we still care about types.
I second on that, a lot of people who uses Python or Ruby, end up writing their own type system
Really? I can honestly say I have never felt the need to invent a type system for Python. The one occasion I have made use of type annotations even caused me more trouble than it was worth (it caught one error that would have come out in testing after I spent hours working out how to break the circular dependencies that arose from trying to formalise duck-typing).
(which is a major reason why language like scala becomes more and more popular and its user base has a lot of former dynamic language users).
The impression that I'm getting from colleagues is that Scala is busily shooting itself in the foot at the moment, so I'm wary of taking lessons from it. Disclaimer: none of us are habitual Scala programmers, so take our collective opinions with a small mountain of salt.
This is especially true for library and framework developers, where you want to capture issues early, e.g. by forcing policies and make sure user defined class is deriving from a common base class and some magic happens behind the scene.
Python isn't a language that does forcing easily or well. Please correct me if I'm wrong, but I've always thought that was to a large extent deliberate. It may be unpopular in general computing right now, but we've always dealt with such potential problems with documentation. (I may be slightly bitter at the moment. I had to spend far too long yesterday reading the code of a C library because the limited documentation failed to mention quite a lot of things, and the examples of how to use it managed to be both trivial and misleading.) -- Rhodri James *-* Kynesim Ltd
Dan Sommers writes:
How would I "think of types as collections of their instances"?
The canonical example of a type as a collection of instances is an enumeration, the simplest (useful) example of which is bool = {False, True}. In pre-big-integer Python, in principle you could do the same thing with the collection of all 2^64-bit bit patterns, with addition defined by a 2^64 x 2^64 tables with rows and columns indexed by the bit patterns and the results in the table cells. So a type is a tuple of a set and operations, which can also be defined as sets of the above form. Floats would have the same underlying set and different tables.
For example, in what sense is the type list a collection of instances of lists?
This involves infinite sets, but in principle can be thought of in the same way.
In my mind, a type is a description/container/shortand for a collection of properties or behaviors of instances of that type.
That's one way to think about it, of course. But the strong intuitions about the numeric tower (a natural number *is* an integer, an integer *is* a real number, and so on) as well as some useful but (intuitively) more artificial ideas such as a bool *is* a natural number are just as well expressed as set inclusions. This is useful in type theory, but explaining "how" is way beyond the scope of this post (and this whole list, in fact).
On 6/18/19 1:25 PM, Stephen J. Turnbull wrote:
Dan Sommers writes:
How would I "think of types as collections of their instances"?
The canonical example of a type as a collection of instances is an enumeration, the simplest (useful) example of which is bool = {False, True}.
And now the light goes on. :-) [...]
In my mind, a type is a description/container/shortand for a collection of properties or behaviors of instances of that type.
That's one way to think about it, of course. But the strong intuitions about the numeric tower (a natural number *is* an integer, an integer *is* a real number, and so on) as well as some useful but (intuitively) more artificial ideas such as a bool *is* a natural number are just as well expressed as set inclusions. This is useful in type theory, but explaining "how" is way beyond the scope of this post (and this whole list, in fact).
Thanks, Stephen; you've done just enough to give me a good shove in the right direction.
On Sun, 16 Jun 2019 at 12:54, Franklin? Lee <leewangzhong+python@gmail.com> wrote:
On Sat, Jun 15, 2019 at 10:26 PM Guido van Rossum <guido@python.org> 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.
Note that making new operators means class containment relationships can't be used as normal comparisons, such as for `sort`, especially of nested comparables such as tuples of classes. I'm not sure how to define a sort key that works even for a simple list of classes, other than to create a wrapper which implements class comparisons.
The subclass relationship between classes defines a partial rather than total order so it can't be used with a normal sorting algorithm. In general sorting a poset requires all-to-all O(N**2) comparison (worst case: only one pair of objects is comparable). You can sort comparable classes with something like: key = cmp_to_key(lambda a, b: issubclass(b, a) - issubclass(a, b)) -- Oscar
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. -- Rhodri James *-* Kynesim Ltd
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. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
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?
On Mon, Jun 17, 2019 at 12:54 PM Andrew Barnert <abarnert@yahoo.com> wrote:
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.
I'm not sure I agree. You can't compare numbers and strings in Python 3, but we happily use + and <= for both. So the argument that different kinds of objects need different operators feels like it doesn't get to the heart of the matter here.
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.
I just gave a good reason (signaling to the reader that we're in meta-land).
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]
Is this any more bizarre than that s[0] == s[0][0] for any non-empty Python string?
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.
That's where I started. I also provided an argument that *if* something needs to be changed it should *not* be to introduce <= for types.
[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?
Right. This seems immaterial to the discussion (looks like you've been nerd-sniped :-). -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
On Jun 17, 2019, at 13:09, Guido van Rossum <guido@python.org> wrote:
On Mon, Jun 17, 2019 at 12:54 PM Andrew Barnert <abarnert@yahoo.com> wrote:
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.
I'm not sure I agree. You can't compare numbers and strings in Python 3, but we happily use + and <= for both. So the argument that different kinds of objects need different operators feels like it doesn't get to the heart of the matter here.
In Python, Integers, strings, and types are different _types_ of object, but they’re all the same _kind_. There’s just one syntax and one set of evaluation rules that apply to all types of values, including types themselves. That’s what’s different from Scala, etc., where types are not the same kind of thing as values, and <: isn’t an operator on values that can be overloaded by the type, but a piece of special syntax used in completely different parts of the language grammar that only operate on types. Sure, completely different syntax doesn’t absolutely require different spelling (see [] for indexing and specialization in Scala, or : in dict displays and compound statements in Python), but it usually implies it, at least as a default. And sure, you can always add new operators as syntactic sugar even when they aren’t necessary, but it’s only occasionally a good idea.
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]
Is this any more bizarre than that s[0] == s[0][0] for any non-empty Python string?
Lots of things are different between Python and Scala, and most of them are not bizarre. But that doesn’t mean they don’t have natural consequences. Variables not being lvalues isn’t bizarre, but it does imply, e.g., no equivalent to C++ operator=. And type being a type isn’t bizarre, but it does imply no need for separate syntax for type computation.
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.
That's where I started. I also provided an argument that *if* something needs to be changed it should *not* be to introduce <= for types.
I agree that <= is not as good a spelling as <: for subclass. But I don’t think it’s that bad; it’s more than good enough for the rare cases where someone needs so much type comparison that they need operators. Especially since it already works today (with a simple metaclass). But even if it is worth adding an operator to type, I think it’s still likely not worth making it a new operator with a new dunder and so on.
[1] Technically,
Right. This seems immaterial to the discussion (looks like you've been nerd-sniped :-).
Well, there’s a reason it’s buried in a footnote. I didn’t think you really wanted to discuss type theory; even though you brought it up. But just in case… :)
17.06.19 17:47, Guido van Rossum пише:
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.
Then perhaps we should start to use <: for sets and left < and <= for types that support full ordering.
`<:` kind of notation would look more clear, I agree. My proposition came after thinking the wording used in Python. issubclass() - is subclass? By definition, subclass reminds me set theory. https://en.wikipedia.org/wiki/Subclass_(set_theory) which also has a relativity with Subtyping as Guido pointed out. And, we have operator support for set() as you can see here https://docs.python.org/3/library/stdtypes.html#set `set <= other` With this logic, since Python has its own way of being practical and predictable in some ways, I would except to have an operator like `<:`, which some other languages already possess. A <: B against issubclass(A, B) looks more elegant, and purpose driven syntax like most of other types. I see that there is also `issubset` method which is equivalent to `set <= other`. Therefore I find this a little bit inconsistent that we don't apply the similar logic for issubclass. I don't know if we could achieve same performance of issubclass itself with the operator (I think we can) but even it's not the case, people who uses Python to write their scripts very fast, that would be a lovely addition.
On Tue, Jun 18, 2019 at 5:01 AM Emin Bugra Saral via Python-ideas <python-ideas@python.org> wrote:
`<:` kind of notation would look more clear, I agree.
My proposition came after thinking the wording used in Python.
issubclass() - is subclass?
By definition, subclass reminds me set theory. https://en.wikipedia.org/wiki/Subclass_(set_theory) which also has a relativity with Subtyping as Guido pointed out.
And, we have operator support for set() as you can see here https://docs.python.org/3/library/stdtypes.html#set `set <= other`
With this logic, since Python has its own way of being practical and predictable in some ways, I would except to have an operator like `<:`, which some other languages already possess.
A <: B against issubclass(A, B) looks more elegant, and purpose driven syntax like most of other types.
I see that there is also `issubset` method which is equivalent to `set <= other`. Therefore I find this a little bit inconsistent that we don't apply the similar logic for issubclass.
Adding a new operator means more to learn for people reading code. It's difficult to search for operators, especially when you're new to Python. The @ operator is less bad, in that it's (usually) specific to Numpy code, and it will be ubiquitous enough among Numpy users that they'll pick it up along the way (either in a tutorial or otherwise). Even if it were more bad, matrix multiplication is usually in complex-enough expressions that the new operator helps readability, and the costs are outweighed by the benefits. There is also a domain advantage, because the people reading and writing the expressions are used to expressing those lines using mathematical symbols. For example, A @ A.T @ v + B @ B.T @ v is better than A.dot(A.T).dot(v).__add__(B.dot(B.T).dot(v)) and it's easier to see that you can refactor the first as (A @ A.T + B @ B.T) @ v than the second. On the other hand, type comparison is NOT often used in the middle of complex expressions, because the result of a type comparison is bool, and you don't often do much arithmetic with bools. There isn't much chaining or nesting. The people reading and writing type expressions are general programmers, NOT mathematicians or scientists. For example, if (A <: B or A <: C) and A <: D: is not much better than if issubclass(A, (B, C)) and issubclass(A, D): especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:. To show that you really do need the feature, you need to show the complex expressions you write with issubclass that would be improved by using an operator.
I don't know if we could achieve same performance of issubclass itself with the operator (I think we can) but even it's not the case, people who uses Python to write their scripts very fast, that would be a lovely addition.
I believe the performance cost will be negligible. A function call requires a lookup and a call. An operator requires one or more lookups and a call. However, the bigger cost will be in grabbing the MRO, iterating through it, and checking for virtual subclassing. You're also not going to be doing type comparisons in a huge loop.
If we want to avoid new operators, I think that the existing “from” keyword is also a good candidate: if A from (B, C) and A from D: ... I’m still skeptical of the value of this feature, though. Brandt
On Jun 19, 2019, at 08:56, Franklin? Lee <leewangzhong+python@gmail.com> wrote:
On Tue, Jun 18, 2019 at 5:01 AM Emin Bugra Saral via Python-ideas <python-ideas@python.org> wrote:
`<:` kind of notation would look more clear, I agree.
My proposition came after thinking the wording used in Python.
issubclass() - is subclass?
By definition, subclass reminds me set theory. https://en.wikipedia.org/wiki/Subclass_(set_theory) which also has a relativity with Subtyping as Guido pointed out.
And, we have operator support for set() as you can see here https://docs.python.org/3/library/stdtypes.html#set `set <= other`
With this logic, since Python has its own way of being practical and predictable in some ways, I would except to have an operator like `<:`, which some other languages already possess.
A <: B against issubclass(A, B) looks more elegant, and purpose driven syntax like most of other types.
I see that there is also `issubset` method which is equivalent to `set <= other`. Therefore I find this a little bit inconsistent that we don't apply the similar logic for issubclass.
Adding a new operator means more to learn for people reading code. It's difficult to search for operators, especially when you're new to Python.
The @ operator is less bad, in that it's (usually) specific to Numpy code, and it will be ubiquitous enough among Numpy users that they'll pick it up along the way (either in a tutorial or otherwise). Even if it were more bad, matrix multiplication is usually in complex-enough expressions that the new operator helps readability, and the costs are outweighed by the benefits. There is also a domain advantage, because the people reading and writing the expressions are used to expressing those lines using mathematical symbols.
For example, A @ A.T @ v + B @ B.T @ v is better than A.dot(A.T).dot(v).__add__(B.dot(B.T).dot(v)) and it's easier to see that you can refactor the first as (A @ A.T + B @ B.T) @ v than the second.
On the other hand, type comparison is NOT often used in the middle of complex expressions, because the result of a type comparison is bool, and you don't often do much arithmetic with bools. There isn't much chaining or nesting. The people reading and writing type expressions are general programmers, NOT mathematicians or scientists.
For example, if (A <: B or A <: C) and A <: D: is not much better than if issubclass(A, (B, C)) and issubclass(A, D): especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:.
To show that you really do need the feature, you need to show the complex expressions you write with issubclass that would be improved by using an operator.
I don't know if we could achieve same performance of issubclass itself with the operator (I think we can) but even it's not the case, people who uses Python to write their scripts very fast, that would be a lovely addition.
I believe the performance cost will be negligible. A function call requires a lookup and a call. An operator requires one or more lookups and a call. However, the bigger cost will be in grabbing the MRO, iterating through it, and checking for virtual subclassing. You're also not going to be doing type comparisons in a huge loop. _______________________________________________ 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/3ZOPAL... Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Jun 20, 2019 at 2:07 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
For example, if (A <: B or A <: C) and A <: D: is not much better than if issubclass(A, (B, C)) and issubclass(A, D): especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:.
Please can people stop trotting out this tired argument? I just typed "<:" (without the quotes) into Google - or rather, into my Chrome omnibar - and the first hit was a Stack Overflow question regarding the "<:" operator in Scala, the second is Scala documentation about "Upper Type Bounds" which looks plausible, and then there are a few others that may or may not be related. Symbols CAN be searched for, both in Google and in many documentation tools. ChrisA
On Wed, Jun 19, 2019 at 11:27 AM Chris Angelico <rosuav@gmail.com> wrote:
On Thu, Jun 20, 2019 at 2:07 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
For example, if (A <: B or A <: C) and A <: D: is not much better than if issubclass(A, (B, C)) and issubclass(A, D): especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:.
Please can people stop trotting out this tired argument? I just typed "<:" (without the quotes) into Google - or rather, into my Chrome omnibar - and the first hit was a Stack Overflow question regarding the "<:" operator in Scala, the second is Scala documentation about "Upper Type Bounds" which looks plausible, and then there are a few others that may or may not be related.
Symbols CAN be searched for, both in Google and in many documentation tools.
It's still harder. E.g. the wikipedia article on subtyping does not show in the search results for "<:", and searching for "<: wikipedia" ignores the "<:" entirely and just searches for "wikipedia". -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
On Thu, Jun 20, 2019 at 4:31 AM Guido van Rossum <guido@python.org> wrote:
On Wed, Jun 19, 2019 at 11:27 AM Chris Angelico <rosuav@gmail.com> wrote:
On Thu, Jun 20, 2019 at 2:07 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
For example, if (A <: B or A <: C) and A <: D: is not much better than if issubclass(A, (B, C)) and issubclass(A, D): especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:.
Please can people stop trotting out this tired argument? I just typed "<:" (without the quotes) into Google - or rather, into my Chrome omnibar - and the first hit was a Stack Overflow question regarding the "<:" operator in Scala, the second is Scala documentation about "Upper Type Bounds" which looks plausible, and then there are a few others that may or may not be related.
Symbols CAN be searched for, both in Google and in many documentation tools.
It's still harder. E.g. the wikipedia article on subtyping does not show in the search results for "<:", and searching for "<: wikipedia" ignores the "<:" entirely and just searches for "wikipedia".
Fair. But it keeps being said as "you can't search for", which at best is an exaggeration. There is a related problem with symbols in that they often have multiple meanings (if you search for info about "@" in a Python context, you'll get both matrix multiplication and decorators), but they are still searchable. (And maybe if people stop using "they're not searchable" as an argument, the tools that ARE completely unable to search for symbols will be seen as flawed tools.) ChrisA
Python's own docs' search doesn't seem to recognize the <= symbol. Google does, but if one doesn't know that, then one won't try it. Google inconsistently decides when and which symbols are considered word chars, and I don't know whether the rules are even documented. Perhaps `help` should be the canonical way to find initial info on operators. The more reliably useful `help` is, the more people will recommend and get in the habit of using it. The current docs for `help` say that a string argument will be interpreted as an identifier, keyword, or "documentation topic" (such as "LISTS"), but it says nothing about symbols. On 3.6.6, calling `help('+')` prints out the documentation for operator precedence, which is kind of jumping into the intermediate part of the pool. Instead, it can explain that the symbol is used as both a unary and binary operator (giving examples of each), say that addition is typically numerical add or string concat, mention that the operator looks for the special method __add__/__pos__, point to related operators (like +=), and point to more info on operators in general (which will point to operator overloading). On Wed, Jun 19, 2019, 15:19 Chris Angelico <rosuav@gmail.com> wrote:
On Thu, Jun 20, 2019 at 4:31 AM Guido van Rossum <guido@python.org> wrote:
On Wed, Jun 19, 2019 at 11:27 AM Chris Angelico <rosuav@gmail.com>
On Thu, Jun 20, 2019 at 2:07 AM Franklin? Lee <leewangzhong+python@gmail.com> wrote:
For example, if (A <: B or A <: C) and A <: D: is not much better than if issubclass(A, (B, C)) and issubclass(A, D): especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:.
Please can people stop trotting out this tired argument? I just typed "<:" (without the quotes) into Google - or rather, into my Chrome omnibar - and the first hit was a Stack Overflow question regarding the "<:" operator in Scala, the second is Scala documentation about "Upper Type Bounds" which looks plausible, and then there are a few others that may or may not be related.
Symbols CAN be searched for, both in Google and in many documentation
tools.
It's still harder. E.g. the wikipedia article on subtyping does not show in the search results for "<:", and searching for "<: wikipedia" ignores
wrote: the "<:" entirely and just searches for "wikipedia".
Fair. But it keeps being said as "you can't search for", which at best is an exaggeration. There is a related problem with symbols in that they often have multiple meanings (if you search for info about "@" in a Python context, you'll get both matrix multiplication and decorators), but they are still searchable.
(And maybe if people stop using "they're not searchable" as an argument, the tools that ARE completely unable to search for symbols will be seen as flawed tools.)
ChrisA _______________________________________________ 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/YMFBBD... Code of Conduct: http://python.org/psf/codeofconduct/
On 6/19/19 8:56 AM, Franklin? Lee wrote:
For example, if (A <: B or A <: C) and A <: D: This expression makes makes very clear the high-level logic being used to determine the relationships between A, B, C, and D that is being checked, and I just need to lookup what <: means to understand the nature of the comparisons. is not much better than if issubclass(A, (B, C)) and issubclass(A, D): This expression makes it very clear that a class hierarchy relationship is being checked, but I still need to reach for the reference manual to understand the semantics of a tuple being passed as an argument to issubclass(). It is not at all intuitive that
especially if you don't know what either of those mean. You can search for issubclass, but you can't search for <:. I generally find Google searches to be useless for most operators and keywords in any language when you are looking for reference information. It is generally faster to search for online reference docs for the language and head straight to the index page. Now, whether
issubclass(A, (B, C)) means "Is A a subclass of B or a subclass of C?" when it could also mean "Is A a subclass of both B and C?". people remember how to use indexes in the age of "search for everything" is another discussion altogether.
To show that you really do need the feature, you need to show the complex expressions you write with issubclass that would be improved by using an operator. I agree, but as I pointed out above, it doesn't have to be very complex. I think a real-world example written both ways would be very helpful to the discussion.
-- ----------------------------------------- From there to here, from here to there, funny things are everywhere. -- Theodore Geisel
On Wed, Jun 19, 2019, 7:35 PM Jeffrey Kintscher <websurfer@surf2c.net> wrote:
It is not at all intuitive that
issubclass(A, (B, C))
means "Is A a subclass of B or a subclass of C?" when it could also mean "Is A a subclass of both B and C?".
I've used issubclass() maybe 20 times in more than 20 years programming Python. I know the correct meaning. But sure, I can imagine not knowing which of the two things you mention is the meaning. Either could be useful. How many times would you need to look it up?! For folks who actually use issubclass() fairly often, that came be a burden. For those of us who rarely use it, consulting the docs once a year also isn't a burden. This just doesn't warrant new syntax.
On 6/20/19 3:03 PM, David Mertz wrote:
On Wed, Jun 19, 2019, 7:35 PM Jeffrey Kintscher <websurfer@surf2c.net <mailto:websurfer@surf2c.net>> wrote:
It is not at all intuitive that
issubclass(A, (B, C))
means "Is A a subclass of B or a subclass of C?" when it could also mean "Is A a subclass of both B and C?".
I've used issubclass() maybe 20 times in more than 20 years programming Python. I know the correct meaning.
But sure, I can imagine not knowing which of the two things you mention is the meaning. Either could be useful. How many times would you need to look it up?!
For folks who actually use issubclass() fairly often, that came be a burden. For those of us who rarely use it, consulting the docs once a year also isn't a burden.
This just doesn't warrant new syntax.
I agree that the implementation cost (i.e development, documentation, and support) appears to outweigh the benefits. While I think the new operators would make the logic easier to read, I haven't seen anything in the discussions showing that developers would use it often enough to justify the implementation cost. //Jeff -- ----------------------------------------- From there to here, from here to there, funny things are everywhere. -- Theodore Geisel
participants (23)
-
Anders Hovmöller
-
Andrew Barnert
-
Andrew Svetlov
-
Brandt Bucher
-
Brett Cannon
-
Chris Angelico
-
Christian Heimes
-
Christopher Barker
-
Dan Sommers
-
David Mertz
-
Emin Bugra Saral
-
eminbugrasaral@me.com
-
Franklin? Lee
-
Guido van Rossum
-
Jeffrey Kintscher
-
Joao S. O. Bueno
-
Oscar Benjamin
-
Rhodri James
-
Serge Matveenko
-
Serhiy Storchaka
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Yanghao Hua