[Python-ideas] Re: mro and super don't feel so pythonic
Stephen J. Turnbull writes: > It's usually helpful to assume that if you parse someone's statement > as nonsense, then probably you parsed it wrong. Sorry, s/wrong/inconsistent with the statement's intended meaning/. Obviously the statement was parsed correctly as English. It's "wrong" only in the sense that the conversation will usually move along more quickly and productively if you try to reparse it meaningfully. ___ 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/R54L3UGEYAIR4HSI4YUHX3HOOTMIRAMX/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > On Sat, Apr 23, 2022 at 10:18:05PM +0900, Stephen J. Turnbull wrote: > > malmiteria writes: > > > > If O1 and O2 are refactored into N1(GP) and N2(GP) > > > the MRO as it was before refactoring was essentially N1, GP, N2, GP, > > > as what was O1 before refactoring is equivalent to N1, GP after > > > refactoring. > > > After refactoring, the MRO is now N1, N2, GP. Which do behave > > > differently, in general. > > > > Nobody denies that. > > I denied the first part, and still do. I meant "nobody denies that behavior under [N1, GP, N2] may differ from that under [N1, N2, GP]". I'm sure you don't deny that. The point of malmiteria's "essentially", I assumed, was that the sequences were representative search orders through the program text, or something like that. Not MROs, despite what was written there. It's usually helpful to assume that if you parse someone's statement as nonsense, then probably you parsed it 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/OARF47BZCLVXOYOPWAVROS3HW2KYEZ5U/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Stephen J. Turnbull writes: > PermissionsMixin is documented to be *abstract* -- there are *no* > default permissions in it. It either does nothing or errors when you > try to use the methods it declares.[1] > > The permission-checking is (and must be) your code. For one thing, > that's what "abstract" means, and in any case *permissions will be > defined by your application*, and permissions violations are an > application problem that the app devs should be testing for, if only > because ransomware is a billion-dollar industry. Upstream is not > going to pay your ransom if some hacker walks in a door *you* left > wide-open and steals all your data. Permissions are defined and applied separately. programmers define the permission they wanna see applied. They apply them by inserting PermissionMixin in the Views inheritance tree. The Permission appliance logic is not "django app" specific. > Here's a concrete > implementation of the case, where O1.a and O2.a don't even share any > code, and only N2 overrides a after refactoring a into a parent class > GP. > [...] > That's what I would want. Good for you, but that's aboslutely not what i'm talking about. I'm talking about a refacto of O1 and O2 which would consist of extracting one common parent, so the case where both O's method don't share any code is irrelevant to my point here. Since you wouldn't refactor a common parent if no code is common to both classes. I guess you could if they have common attribute tho, but that's just not what i'm talking about here. Also, I'm talking about a proper refactoring that isn't meant to change the code behavior at all. Extracting a common parent class is a refactoring intended to not change the classes behavior at all : ``` class O1: def method(self): print('GP') print('N1') class O2: def method(self): print('GP') print('N2') ``` Can be refactored like that (renaming O1 into N1, and O2 into N2 so we can know which class is the refactored version when discussing it later on, but real refactoring wouldn't rename it at all): ``` class GP: def method(self): print('GP') class N1(GP): def method(self): super().method() print('N1') class N2(GP): def method(self): super().method() print('N2') ``` This is what most people would consider actual refactoring, as in, it doesn't change the behavior of the code at all. Although some people know about super and MRO in case of MI, so they might be able to spot the potential change in behavior here. If this code is published by a library, as a lib user, doing MI with O1 and O2 will not behave the same as doing MI with N1 and N2 (again, renamed only so we know which is the refactored one in this discussion). It is reasonable to assume not every lib author know about this MI situation, and the breaking change this refactoring is. As a lib user, how do you prevent this from breaking your code? Same can be said of the opposite refactoring, consisting of reinserting GP in N1 and N2 to only provide O1 and O2. In other terms, super and MRO aren't so reliable, and that's an example of that. Steven D'Aprano writes: > No, that's impossible. That is an inconsistent MRO: it has GP listed > twice, which is a bug. I was just making the point that the actual lines of code being executed before the refactoring would have applied in this order, which has, after refactoring, the lines in GP appear twice. Now, why oh why would a class apearing twice be a bug? Essentially what it means is that that classe's methods can be called twice. So what? How's that a bug? Although, if you're saying it's not possible *today*, and would be considered a bug *of today's* MRO, i understand. But then, what's your point? changing that isn't an issue, we can introduce some modules to give the choice to the programmers if they want one class to appear multiple times, or not. And default to today's behavior so it's not a breaking change. This would make it possible, if wanted, for a class to appear multiple times, and that would definitely be by design, so what's your point? You seem to believe that MI is supposed to be the way it already is, and any attempts at changing it is blaspheme. I'm not saying that to tease you, it really feels like the idea of changing it repulses you on its own. And that you're saying it's a bug as a slightly more specific way of saying "it's bad, period". Or maybe "python shouldn't behave like that, and i wouldn't have it any other way". As much as your entitled to your feelings / opinions (idk which words applies best here), I don't think they make (here) for a compeling argument. > Pretty much. In general, any change to the MRO is a potential breaking > change, unless you design your classes very carefully. Yeah, and overall it's a control flow problem. The 'strat' module i've been taking about could be seen as more tooling for control flow in MI. strat
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, Apr 23, 2022 at 10:18:05PM +0900, Stephen J. Turnbull wrote: > malmiteria writes: > > If O1 and O2 are refactored into N1(GP) and N2(GP) > > the MRO as it was before refactoring was essentially N1, GP, N2, GP, > > as what was O1 before refactoring is equivalent to N1, GP after > > refactoring. > > After refactoring, the MRO is now N1, N2, GP. Which do behave > > differently, in general. > > Nobody denies that. I denied the first part, and still do. There is no possible valid MRO that goes [N1, GP, N2, GP] because that lists the same class twice. Such a thing was possible in Python 1.x and 2.x "old-style" (classic) classes, it was a bug in the way classic classes generated the MRO, and it caused bugs in code that hit those cases. (Fortunately those cases were rare, so most people didn't notice.) -- Steve ___ 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/UEGNMUD3P55W4C6SJ6IWGTZT7QFPRROU/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
malmiteria writes: > to give you exemples of problems : > 1) let's start with a django problem : > ``` > class MyView(ModelView, PermissionMixin): pass > ``` > > Since it's mostly made out of django stuff, it's likely there > wouldn't be automated testing to check if the permissions are > indeed required when attempting to visit whatever resource MyView > serves. After all, automated testing should test your code, not the > library you're importing's code. PermissionsMixin is documented to be *abstract* -- there are *no* default permissions in it. It either does nothing or errors when you try to use the methods it declares.[1] The permission-checking is (and must be) your code. For one thing, that's what "abstract" means, and in any case *permissions will be defined by your application*, and permissions violations are an application problem that the app devs should be testing for, if only because ransomware is a billion-dollar industry. Upstream is not going to pay your ransom if some hacker walks in a door *you* left wide-open and steals all your data. I wish you'd stop making up non-problems and show us either working code where you had to do something horrible (like use _as_parent) because of the MRO, or non-working code where you have to restart from scratch because of the MRO. By "working" I mean it has some use other than making the point that Python's use of the MRO sucks. > If O1 and O2 are refactored into N1(GP) and N2(GP) > the MRO as it was before refactoring was essentially N1, GP, N2, GP, > as what was O1 before refactoring is equivalent to N1, GP after > refactoring. > After refactoring, the MRO is now N1, N2, GP. Which do behave > differently, in general. Nobody denies that. [...] > And no, class.method doesn't work in this case either. I don't understand what you mean by that. Here's a concrete implementation of the case, where O1.a and O2.a don't even share any code, and only N2 overrides a after refactoring a into a parent class GP. % python3.10 Python 3.10.4 (main, Mar 25 2022, 04:37:13) [Clang 13.0.0 (clang-1300.0.29.3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> class GP: ... def a(s): ... print('This is GP') ... >>> class N1(GP): ... pass ... >>> class N2(GP): ... def a(s): ... print('This is N2') ... >>> class C(N1, N2): ... def b(s): ... print('super: ', super().a(s)) ... print('N1: ', N1.a(s)) ... print('N2: ', N2.a(s)) ... print('GP: ', GP.a(s), " # for completeness, the N1 case is the important one') ... >>> c = C() >>> c.b() super: This is N2 N1: This is GP N2: This is N2 GP: This is GP # for completeness, the N1 case is the important one >>> That's what I would want. I don't have to go farther down the hierarchy than the class I explicitly declared to get the result I want. What do you mean by "work"? Or do you mean a different case? If so, what is it? Steve Footnotes: [1] It could be "abstract" in the sense that there is a standard way to express permissions defined by the methods, but none are loaded. Then it does nothing when its methods are invoked. Or it could be abstract in the sense of providing unimplemented methods, in which case they will error. ___ 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/URP3XQ3566R5YJ7S5VIZQ5HSNKNNQ43P/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Thanks for your comments! On Fri, 22 Apr 2022 at 23:27, Steven D'Aprano wrote: > > On Fri, Apr 22, 2022 at 08:46:38PM +1100, Matsuoka Takuo wrote: > > > > So I may not have been told a refactoring like that shouldn't involve > > a new instance of overriding, but may I have essentially been told I > > shouldn't refactor at all if I didn't want to create breaking changes? > > Pretty much. In general, any change to the MRO is a potential breaking > change, unless you design your classes very carefully. Great. That's true. Best regards, Takuo Matsuoka ___ 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/R7FS3D3USDMNJJDKGHPHDQLFEQ63CZAW/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, Apr 22, 2022 at 08:46:38PM +1100, Matsuoka Takuo wrote: > On Fri, 22 Apr 2022 at 15:47, Christopher Barker wrote: > > > > Sure -- but there's nothing special or difficult here -- refactoring > > can create breaking changes. I believe it was part of Hettinger's > > thesis in "Super Considered Super" that the use of super() is part > > of the API of a class hierarchy. Indeed, the MRO of a class > > hierarchy is part of the API. If you change the MRO, it is a > > potentially breaking change, just as if a method is added or > > removed, or renamed, or ... > > So I may not have been told a refactoring like that shouldn't involve > a new instance of overriding, but may I have essentially been told I > shouldn't refactor at all if I didn't want to create breaking changes? Pretty much. In general, any change to the MRO is a potential breaking change, unless you design your classes very carefully. See for example this Django ticket: https://code.djangoproject.com/ticket/29735?cversion=0_hist=3 **Inheritance is hard.** The easy cases are so amazingly easy that people are shocked when they run into complicated inheritance designs and discover how hard they are. Some people respond by refusing to believe that inheritance is hard, and insisting that there has to be a Magic Bullet that will make everything Just Work, or they blame super(). But the problems aren't with super(). Other people respond by saying that inheritance is just a tool, and if the tool doesn't work you should use a different tool which is better suited to what you are trying to do. That tool might be to restrict the way you use inheritance to a smaller subset, or to use delegation, etc. -- Steve ___ 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/OBQNROHI5L3KZ6HO2ID7P6FBJZSNDYVS/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, Apr 20, 2022 at 03:43:44PM -, malmiteria wrote: > to give you exemples of problems : > 1) let's start with a django problem : > ``` > class MyView(ModelView, PermissionMixin): pass > ``` > doesn't apply any of the PermissionMixin logic to the view. > It doesn't raise a single error either. Is it supposed to work, or is the bug in your code, not the framework? If it is a bug in the framework, have you reported it as a bug to Django, and if not, why not? > Since it's mostly made out of django stuff, it's likely there wouldn't > be automated testing to check if the permissions are indeed required > when attempting to visit whatever resource MyView serves. After all, > automated testing should test your code, not the library you're > importing's code. You should be testing MyView to ensure that the permissions are required. If you don't have a test that MyView requires testing, then somebody could refactor MyView and remove the permission stuff, and you will never know. > The only way to tell those permission aren't applied, in this case, is > to actually see the bug happen IRL. Not the only way. The right way is to test MyView to ensure it is doing what you expect. > 2) Another one, straight from django docs : > https://docs.djangoproject.com/fr/4.0/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin.get_test_func Here's the link for those who can't read French: https://docs.djangoproject.com/en/4.0/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin.get_test_func (Your English is much better than my French.) The problem here is explained in the docs: "Due to the way UserPassesTestMixin is implemented, you cannot stack them in your inheritance list." And then: "If TestMixin1 would call super() and take that result into account, TestMixin1 wouldn’t work standalone anymore." So the problem is that UserPassesTestMixin is not designed to be the top node in a diamond (that is, you can't inherit from it more than once). This is an example why multiple inheritance must be *cooperative*. Due to the tight coupling between classes in MI, you have to carefully design your classes to cooperate. I *guess* that the fundamental problem here is that Django is where Zope and Plone were six years ago: stuck with an overly complicated and complex framework based on MI, before their move to preferring composition(?) in version 4. (I'm *totally* guessing here: I'm not an expert on Django, or Zope. I could be wrong.) > Some would argue the proper way to do multiple inheritance implies > having one single parent class all classes you inherit from do > themselves inherit from. > > This allows you to use super in those class, and still allows you to > inherit from each of them individually, as needed, without risking a > super call to target object, in which case you'd face the problem that > object doesn't have whatever method you're trying to access. Correct. > What happens when the common parent class raises NotImplemented errors? The same as any other exception: if your class raises an exception, it is either an internal bug in the class, or a documented exception as part of the class' API. So if your common parent class raises NotImplementedError, that is either a bug in your common parent class, or a bug in your subclass, for triggering the condition that is documented as raising NotImplementedError. > You can't use super in any of it's child class, and any of its child > class using super would work only under MI, if not the last parent > inherited from. The whole point of that common parent is to catch any methods before they hit the ultimate base class, object. > In other term, you render those 'independant' objects not independant anymore. Classes in inheritance hierarchies are not independent. They are heavily dependent and tightly coupled. This is why people prefer the less-tightly coupled composition pattern over inheritance. > Note that this django docs explicitely states it is not possible to > practice multiple inheritance in this case, which is my point : Right. Because you have to design your classes very carefully to work correctly under MI, and Django have not done that in this case. (They may or may not have a good reason for that.) > people don't know a way out of super for MI cases, when super doesn't work. > > 3) My gobelin exemple is another case. > What if you want to inherit from multiple parent 'as is', instead of > having them ignore their respective parent (GP) because this parent > (GP) is reoccuring in the inheritance tree? We've answered this many times. > 4) Lib refactoring are breaking changes > A Lib author refactoring his code by extracting a class as a parent > class of multiple of the class provided is introducing a breaking > change. > Because any user's code inheriting from at least 2 of the class > impacted by this refactoring will now exhibit a different
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, 22 Apr 2022 at 15:47, Christopher Barker wrote: > > Sure -- but there's nothing special or difficult here -- refactoring can > create breaking changes. I believe it was part of Hettinger's thesis in > "Super Considered Super" that the use of super() is part of the API of a > class hierarchy. Indeed, the MRO of a class hierarchy is part of the API. If > you change the MRO, it is a potentially breaking change, just as if a method > is added or removed, or renamed, or ... So I may not have been told a refactoring like that shouldn't involve a new instance of overriding, but may I have essentially been told I shouldn't refactor at all if I didn't want to create breaking changes? I feel that's too much to be a kind alert since it seems just easy to avoid introducing a new instance of over-riding. (I understand super would require more care to be used in the refactoring, even though a little more, I think.) Best regards, Takuo Matsuoka ___ 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/FWT2ZWFRIATQZLMKHSQVNW4XGI5BKVU6/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
> > On Thu, 21 Apr 2022 at 02:45, malmiteria wrote: > > 4) Lib refactoring are breaking changes > > A Lib author refactoring his code by extracting a class as a parent > class of multiple of the class provided is introducing a breaking change. > > > After refactoring, the MRO is now N1, N2, GP. Which do behave > differently, in general. > Sure -- but there's nothing special or difficult here -- refactoring can create breaking changes. I believe it was part of Hettinger's thesis in "Super Considered Super" that the use of super() is part of the API of a class hierarchy. Indeed, the MRO of a class hierarchy is part of the API. If you change the MRO, it is a potentially breaking change, just as if a method is added or removed, or renamed, or ... Nothing to see here -- this is all deliberate, and useful. -CHB -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython ___ 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/TLMQKK4OAPALUZJHZVJI7BLZZ4PQ7QVF/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Thu, 21 Apr 2022 at 02:45, malmiteria wrote: > > 4) Lib refactoring are breaking changes > A Lib author refactoring his code by extracting a class as a parent class of > multiple of the class provided is introducing a breaking change. > Because any user's code inheriting from at least 2 of the class impacted by > this refactoring will now exhibit a different behavior. > If O1 and O2 are refactored into N1(GP) and N2(GP) > the MRO as it was before refactoring was essentially N1, GP, N2, GP, as what > was O1 before refactoring is equivalent to N1, GP after refactoring. > After refactoring, the MRO is now N1, N2, GP. Which do behave differently, in > general. This seems important. The refactoring can cause a problem if both of O1 and O2 have an attribute (or method) say "a", and O1.a goes to GP, and O2.a goes to N2. While O1.a would more naturally be going to N1 (or some class between N1 and GP), the fact is it must! I don't think I have ever been told a refactoring like that shouldn't involve a new instance of overriding. Is this known to most Python programmers? I wish every Python programmer will know it. Best regards, Takuo Matsuoka ___ 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/F3VEMOUPZ7JQZ3FPQ25HF7HRG7IDCLGZ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Greg Ewing writes: > Even if you do, it's still an arbitrary choice to prefer the leftmost > method, which might be what you want or might not. Yep, i 100% agree with you, and that's (one of) my problems with current MI in python, and the reason i named that thread MRO and super don't feel so pythonic And the fact that this python feature doesn't abide by python's zen is an argument against it. Stephen J. Turnbull writes: > Sure, the too tricky somebody may be a library author (hello, Django) > in which case the person we're worried about is innocent collateral > damage. I'm afraid that person is going to have to put out the effort > to learn what the MRO is and how it works, or consult someone who > already knows. In any case, I don't see evidence that such collateral > damage is anything but a theoretical possibility. That's again the "user's who can't use my feature are the problem, my feature itself doesn't have a problem" mindset. Truth is, user's who can't use a feature properly can be in the wrong, because they didn't learn enough about it, as much as they can be living proof the feature is not mature enough. to give you exemples of problems : 1) let's start with a django problem : ``` class MyView(ModelView, PermissionMixin): pass ``` doesn't apply any of the PermissionMixin logic to the view. It doesn't raise a single error either. Since it's mostly made out of django stuff, it's likely there wouldn't be automated testing to check if the permissions are indeed required when attempting to visit whatever resource MyView serves. After all, automated testing should test your code, not the library you're importing's code. The only way to tell those permission aren't applied, in this case, is to actually see the bug happen IRL. 2) Another one, straight from django docs : https://docs.djangoproject.com/fr/4.0/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin.get_test_func Some would argue the proper way to do multiple inheritance implies having one single parent class all classes you inherit from do themselves inherit from. This allows you to use super in those class, and still allows you to inherit from each of them individually, as needed, without risking a super call to target object, in which case you'd face the problem that object doesn't have whatever method you're trying to access. What happens when the common parent class raises NotImplemented errors? You can't use super in any of it's child class, and any of its child class using super would work only under MI, if not the last parent inherited from. In other term, you render those 'independant' objects not independant anymore. Note that this django docs explicitely states it is not possible to practice multiple inheritance in this case, which is my point : people don't know a way out of super for MI cases, when super doesn't work. 3) My gobelin exemple is another case. What if you want to inherit from multiple parent 'as is', instead of having them ignore their respective parent (GP) because this parent (GP) is reoccuring in the inheritance tree? 4) Lib refactoring are breaking changes A Lib author refactoring his code by extracting a class as a parent class of multiple of the class provided is introducing a breaking change. Because any user's code inheriting from at least 2 of the class impacted by this refactoring will now exhibit a different behavior. If O1 and O2 are refactored into N1(GP) and N2(GP) the MRO as it was before refactoring was essentially N1, GP, N2, GP, as what was O1 before refactoring is equivalent to N1, GP after refactoring. After refactoring, the MRO is now N1, N2, GP. Which do behave differently, in general. If your point is : > I'm afraid that person is going to have to put out the effort > to learn what the MRO is and how it works Then how are any lib user's supposed to account for this case 4? The only way is to never use MI with any class from any lib you're inheriting from... And no, class.method doesn't work in this case either. ___ 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/LJE5RVKUKFPRIQWU6NJYIFIUBU6KIACV/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
malmiteria writes: > Stephen J. Turnbull writes > > Every feature means making an arbitrary choice that may or may > > not be what the programmers wanted. > > I don't think that's what greg meant. I don't either. That's a separate comment that I made about the nature of developing a product (namely, Python itself). Greg wasn't commenting on that, and he may or may not agree with me -- I'm pretty sure he'll *understand* the point. Whether he agrees doesn't matter for the point I was making, which was about how *I* interpret "when faced with uncertainty, refuse to guess." > they can take the time to learn C3 in depth. Which most people > don't, so they are left guessing. So what? It rarely matters, and if it does, it almost never does real harm because people who depend on super in MI contexts generally do know what they're doing and design for success. If it does do harm, somebody was being too tricky for their own good. Sure, the too tricky somebody may be a library author (hello, Django) in which case the person we're worried about is innocent collateral damage. I'm afraid that person is going to have to put out the effort to learn what the MRO is and how it works, or consult someone who already knows. In any case, I don't see evidence that such collateral damage is anything but a theoretical possibility. Steve ___ 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/L4M3N4TNGVS4F7HLGYQ5XT7ADKQGDKAE/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 18/04/22 7:29 pm, malmiteria wrote: It's an arbitrary choice that the C3 feature itself makes, and the programmer is left guessing what that choice was, unless they can take the time to learn C3 in depth. Even if you do, it's still an arbitrary choice to prefer the leftmost method, which might be what you want or might not. The "guessing" in the Zen is a tongue-in-cheek way of referring to picking something as a default when there isn't any strong reason to think it will be what is most often wanted. If there's any literal guessing involved, it's on the part of the language designer. -- Greg ___ 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/JEHUSQKTLQQGA7FEVPMQI5TAZP6VZ4L7/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Stephen J. Turnbull writes > Every feature means making an arbitrary choice that may or may not be > what the programmers wanted. I don't think that's what greg meant. It's not an arbitrary choice between multiple possible features that would cover the same need. It's an arbitrary choice that the C3 feature itself makes, and the programmer is left guessing what that choice was, unless they can take the time to learn C3 in depth. Which most people don't, so they are left guessing. And since the feature doesn't tell what it does, from within the language itself (or in other term, reading the program doesn't tell you what it does), it's fair to say there's some guessing involved in it, for most programmers. ___ 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/5XSJIB5RP6Q3HK3RD5622J3BXLRPJR7K/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Greg Ewing writes: > On 16/04/22 10:46 pm, Steven D'Aprano wrote: > > There is no *guessing* in the C3 linearization algorithm. > > "Guessing" in the context of that Zen line means making an arbitrary > choice that may or may not be what the programmer wants. It doesn't > mean choosing at random. Every feature means making an arbitrary choice that may or may not be what the programmers wanted. That's why we sometimes rewrite stuff in C: because most applications of "such stuff" we want time or space performance more than we want the dynamic power of Python. But we have a requirement (at least a strong suggestion) that where possible C modules should also provide Python implementations so that people who want the power of Python can have it, at some cost in performance. So in the context of the Zen, I suggest we "refuse to guess" *because* that arbitrary choice also forecloses (or at least makes very difficult) other choices. Otherwise, that Zen would discourage adding any features at all! But to me, C3 is hardly arbitrary. The technical sense in which a deterministic algorithm doesn't guess is irrelevant to the Zen, as you point out. But I don't think that's what Steven meant. Someone wrote that C3 is based on 5 requirements, which could also be considered assumptions about what the programmer wants. I don't recall what they are exactly, but they seemed really plausible to me as a guide to what most programmers would want, or at least find acceptable, most of the time. If you're going to call something even in the event of multiple definitions, C3 has benefits (I don't have time to enumerate them right now). I don't think that's an arbitrary guess, and I think that's what Steven meant. But still, what if that's not what the programmer wants? Can they get what they want, *as easily as if the feature didn't exist*? How often does it happen that they can't? I haven't seen any compelling answers to those questions, only cooked-up toy programs whose only known use is to give the answer "yes" to the question "can I find a program where super() and/or C3 can't do the thing I arbitrarily prespecify that the program must do?", and one (1) hearsay story whose "harm" is perfectly well redressed by "OK, don't fix what ain't broke, then". Steve ___ 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/63GGODAVSDZKSNK33SXYZZQFFLN7HY3F/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
I'm a bit late to this conversation, but here i go: Steven d'Aprano writes: > But given the assumptions that: > > - the inheritance model automatically resolves conflicts; > > - the MRO is entirely dependendent on the shape of the inheritance > graph, and not on incidental properties like the name of classes; > > - the inheritance model is consistent, monotonic and preserves local > precedence order (C3 linearization); I believe that those are a bit too much. conflicts can be resolved by redefining the method in the child class, so no need for automation here. As long as super calls allow to pick and chose the parent method you want, so you can explicitely combine them as you want, in the order you want, or simply ignore one if you want. So i wouldn't define 'full MI' with the assumption that "the inheritance model automatically resolves conflicts;" One could say it even gives more power to the programmers, as it would inform them in those 'ambiguous' cases. > - the MRO is entirely dependendent on the shape of the inheritance > graph, and not on incidental properties like the name of classes; This is something we want, yeah, but it is not a given in python... ``` class Top: pass class Left(Top): pass print(Left.__mro__) # Left, Top class Right(Top): pass class Bottom(Left, Right): pass print(Bottom.__mro__) # Bottom, Left, Right, Top ``` As you can see, Left MRO when subclassed by Bottom is different from Left MRO when taken alone. (even if it can be found in a subsequence) This means that a refactoring consisting of extracting the class Top from Left and Right is technically a breaking change, from a lib author point of view. We might wanna get rid of that. > - the inheritance model is consistent, monotonic and preserves local > precedence order (C3 linearization); I'm unclear on what you mean by consistent. Local precedence order should probably be conserved, i'm not arguing against that. But monotonicity, i don't think so. with the exemple above, Bottom MRO could be "Bottom, Left, Top, Right, Top", this is not monotonic, but not inconsistent either. Probably even more consistent? essentially, it could be for any class : "class, [MRO from class first parent], [MRO from the second parent], ..." That would be even more consistent than today's MRO which by subclassing allows MRO injection And there would not be any inconsistent inheritence tree, except maybe if a class happens to be in its own inheritance tree. You also argued somewhere, sorry i can't find it back to quote it, that it's a good thing that an error is raised in case we're doing an inconsistent class hierarchy, but i'd argue it is a problem, since there's no way out this error. Even when you know what you're doing. Those class inheritence trees are barred from the language now, no matter what. Greg Ewings writes: > There's nothing incoherent or inconsistent about the way C++ > and Eiffel do MI. The main difference is that they require you > to explicitly resolve conflicts between inherited methods -- > which is arguably more Pythonic than Python, since they refuse > the temptation to guess. That's actually the very reason why i named this thread "mro and super don't feel so pythonic" Can't agree more with you here. ___ 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/PIP2VRDF7XNYWLQE5YLSLX4JWFGKB6ZM/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 16/04/22 10:46 pm, Steven D'Aprano wrote: On Sat, Apr 16, 2022 at 05:56:13PM +1200, Greg Ewing wrote: There's nothing incoherent or inconsistent about the way C++ and Eiffel do MI. Good thing I never said that they were incoherent or inconsistent. You seemed to be implying that, though. You claim that the C3 algorithm is the only way to get MI that is coherent and consistent. If that's true, then since C++ and Eiffel don't use C3, they must not be coherent and consistent. There is no *guessing* in the C3 linearization algorithm. "Guessing" in the context of that Zen line means making an arbitrary choice that may or may not be what the programmer wants. It doesn't mean choosing at random. -- Greg ___ 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/H7DCU2P2465PWU2NNTLVQURWG6VCIOGT/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 16/04/22 11:13 pm, Steven D'Aprano wrote: So we might say that all inheritance is delegation, but not all delegation is inheritance. We might even go further and say that any delegation to a superclass (not just the direct parent) is a form of manual inheritance. To my way of thinking, delegation is when you call a method of a *different* object. With a super call (either explicit or implicit) you're calling a different method of the *same* object. Think about the ordinary meaning of the word "delegation". When you delegate a task, you give it to someone *else* to do. If instead you just find a different way of doing it yourself, you wouldn't call that delegation. So I would say that none of the things we're talking about here are examples of delegation. -- Greg ___ 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/HE2HDBITU7PLOJCCQ6UKFKZSZDZM44Z6/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, Apr 16, 2022 at 05:27:57PM +1200, Greg Ewing wrote: > On 15/04/22 10:37 pm, Steven D'Aprano wrote: > >If you look at languages that implement MI, and pick the implementations > >which allow it with the fewest restrictions, then that is "full MI". > > >I believe that Python (and other languages) allow MI with > >the smallest set of restrictions, namely that there is a C3 > >linearization possible > > But before Python adopted the C3 algorithm, it was less > restrictive about the inheritance graph. Less restrictive, and *inconsistent* (hence buggy). > So by your definition, current Python does not do full MI! No, I'm excluding inconsistent models of MI. Correctness is a hard requirement. Otherwise we get into the ludicrous territory of insisting that every feature can be implemented with one function: def omnipotent_function(*args, **kwargs): """Function which does EVERYTHING. (Possibly not correctly, but who cares?) """ return None There you go, now we can define an MRO for any class hierarchy imaginable, and dispatch to the next class in that hierarchy, using the same function. It won't work, of course, but if correctness isn't a hard requirement, what does that matter? :-) > >If you have to manually call a specific method, as shown here: > > > >https://devblogs.microsoft.com/oldnewthing/20210813-05/?p=105554 > > > >you're no longer using inheritance, you're doing delegation. > > You could also say that Python automatically delegates to the first > method found by searching the MRO. > > Why is one of these delegation and not the other? That is a very interesting question. As I mentioned earlier, there is a sense that all inheritance is a kind of delegation, and in languages without an explicit super() (or "nextclass", or whatever you want to call it), the only way to get inheritance when you overload a method is to use explicit delegation to your superclass. So we might say that all inheritance is delegation, but not all delegation is inheritance. We might even go further and say that any delegation to a superclass (not just the direct parent) is a form of manual inheritance. But in general, in ordinary language, when we talk about inheritance, we're talking about two (maybe three) cases: 1. Automatic inheritance, when your class doesn't define a method but automatically inherits it from its superclass(es). class Parent: def method(self): pass class Child(Parent): pass assert hasattr(Child, "method") 2. Automatic inheritance when your class overloads a method and calls super() manually to delegate to the superclass(es). class Child(Parent): def method(self): print("Overload") super().method() 3. And more dubiously, but commonly used, when people who don't like super(), or know about it, explicitly delegate to their parent in single inheritance: class Child(Parent): def method(self): print("Overload") Parent.method(self) # Oooh, flashbacks to Python 1.5 -- Steve ___ 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/GOMMXQW4L6OJXO2425DZQE5AERGEMC5G/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, Apr 16, 2022 at 05:56:13PM +1200, Greg Ewing wrote: > On 16/04/22 12:56 pm, Steven D'Aprano wrote: > >If you exclude models of MI which are logically incoherent and > >inconsistent, (such as Python's prior to version 2.3), then Python's > >model of MI is objectively as complete as you can get. > > You seem to be assuming that "full MI" has to include a fully > automatic means of method resolution. How very observant of you, I only mentioned that about a hundred bazillion times so far!!! (Yes, I am frustrated. But cheerfully so.) > There's nothing incoherent or inconsistent about the way C++ > and Eiffel do MI. Good thing I never said that they were incoherent or inconsistent. I'm happy to have vigorous debate, but it would be kinda nice if people would argue against my actual position. As I understand it, C++ and Eiffel still do automatic method resolution, it is only when there is a conflict that they demand you manually resolve the conflict. > The main difference is that they require you > to explicitly resolve conflicts between inherited methods -- Right, another thing which I have mentioned. In that regard, they are sort of like traits, as developed in Squeak. (Scala traits are something different. Another example of different languages using the same term to mean different things.) > which is arguably more Pythonic than Python, since they refuse > the temptation to guess. There is no *guessing* in the C3 linearization algorithm. -- Steve ___ 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/MJNOGXMDLBVBPGMOJ624AOAJHQ3C3TJJ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 16/04/22 12:56 pm, Steven D'Aprano wrote: If you exclude models of MI which are logically incoherent and inconsistent, (such as Python's prior to version 2.3), then Python's model of MI is objectively as complete as you can get. You seem to be assuming that "full MI" has to include a fully automatic means of method resolution. There's nothing incoherent or inconsistent about the way C++ and Eiffel do MI. The main difference is that they require you to explicitly resolve conflicts between inherited methods -- which is arguably more Pythonic than Python, since they refuse the temptation to guess. -- Greg ___ 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/J5I3MLGZPMOKBRTPANQIE74RMRSHUBJM/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 15/04/22 10:37 pm, Steven D'Aprano wrote: If you look at languages that implement MI, and pick the implementations which allow it with the fewest restrictions, then that is "full MI". I believe that Python (and other languages) allow MI with the smallest set of restrictions, namely that there is a C3 linearization possible But before Python adopted the C3 algorithm, it was less restrictive about the inheritance graph. So by your definition, current Python does not do full MI! If you have to manually call a specific method, as shown here: https://devblogs.microsoft.com/oldnewthing/20210813-05/?p=105554 you're no longer using inheritance, you're doing delegation. You could also say that Python automatically delegates to the first method found by searching the MRO. Why is one of these delegation and not the other? -- Greg ___ 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/GJIZENRGIZCDPLXPXQ6MBYKEUR33ZGV5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, Apr 15, 2022 at 05:41:55PM -, malmiteria wrote: > Sticking to the way its done "just" because it's the way it's done > helps stabilising the language, but it makes it possible to miss > improvements. > > Overall, if there's only valid reasons to implement a change, this > change doesn't break anything and there's no valid reason not to > implement it, You can't change existing behaviour without breaking things. > and this change is not "full MI", fine, we're out of > full MI, what's the big deal? The big deal is that right now there are programs which rely on Python providing MI in full generality, including class hierarchies with method conflicts. Whether they should is another question, but they do, and the interpreter resolves those conflicts for them. If you put in restrictions to MI that raises an error on method conflicts, that will break their code, and as a matter of policy that will not happen. Just because the language definition of MI is fully general doesn't mean that frameworks have to use that full generality. Zope and Plone have moved away from using MI to more composition in order to escape some of the problems they were facing. There is nothing wrong with frameworks or libraries introducing their own conventions, enforced by metaclasses or decorators or whatever you want, to implement C++ or Eiffel style restrictions on method conflicts. > Someone mentionned the "class A(B(C)):" syntax was already meaning > something, i've tried a few things, but overall, most scenarios simply > fail with this syntax today. The only one i could make work was "class > A(namedtuple(...not a class...)):" Right. The *syntax* B(C) means to call object B with argument C, and that applies inside class definitions too. You can't change the meaning of that syntax. It will always mean call object B with argument C. Are you aware that class definition syntax accepts arbitrary keyword arguments and passes them on to the `__init_subclass__` method? >>> class A(int, spam=1, eggs=2): ... pass ... Traceback (most recent call last): File "", line 1, in TypeError: A.__init_subclass__() takes no keyword arguments Right now, the only one which has meaning to the interpreter is `metaclass=expression`. > If anyone has any source / talks on that, i would love to read it. Did you read the links to Michele Simionato's posts on Artima I posted? If not, then why should anyone bother sending you more links that you won't read? -- Steve ___ 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/2DJ3HRXBXFQ3QK25TQLO2IPNUIKDCTMM/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, 16 Apr 2022 at 11:00, Steven D'Aprano wrote: > > and therefore > > would become the only thing that offers "full MI", displacing other > > languages. It's a meaningless concept, unless there is some form of > > absolute completeness that can be attained > > Well duh Chris, sometimes I wonder if you read my posts before jumping > in to disagree with me, that is *exactly* what I am arguing. You placed a LOT of caveats on it. I don't count that as "absolute completeness". It is the most complete that YOU, right now, think could ever be possible. > If you exclude models of MI which are logically incoherent and > inconsistent, (such as Python's prior to version 2.3), then Python's > model of MI is objectively as complete as you can get. If you assume that what we know in 2022 is the most we will ever know, then yes, you would be correct. Do you really think that nobody will ever learn anything new about ways of doing MI? I don't know whether you're mistaken or utterly arrogant. > > My view: If a class inherits two parents, in any meaning of the word > > "inherits" that follows the normal expectation that a subclass IS an > > instance of its parent class(es), then it's MI. > > Inheritance and "is-a" relationships are independent. > > In some languages (but not Python), mixins provide inheritance but not > an "is-a" relationship. In Python, virtual subclassing provides "is-a" > without inheritance. Virtual subclassing is still subclassing, just implemented differently. Reassigning to __class__ is still subclassing, just spelled differently. What is "inheritance" if it isn't that is-a relationship? How do you distinguish inheritance from delegation? Is inheritance only a thing if it happens on the line of code that says "class X"? (Not the case in Pike.) Is inheritance only a thing if it happens as the class is first created? (Is the case with mixins.) What's your point? ChrisA ___ 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/EVTHYR56KAKVUF7ZLPVREVHD2M2PI6EL/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, 16 Apr 2022 at 11:07, Chris Angelico wrote: > > On Sat, 16 Apr 2022 at 11:00, Steven D'Aprano wrote: > > > and therefore > > > would become the only thing that offers "full MI", displacing other > > > languages. It's a meaningless concept, unless there is some form of > > > absolute completeness that can be attained > > > > Well duh Chris, sometimes I wonder if you read my posts before jumping > > in to disagree with me, that is *exactly* what I am arguing. > > You placed a LOT of caveats on it. I don't count that as "absolute > completeness". It is the most complete that YOU, right now, think > could ever be possible. For a slightly tangential comparison: If you assume that "numbers" are only those on the real number line, then you assume that returning an error when asking for the square root of a negative number is the ONLY way to do things, and a mathematical library that can handle all real numbers is absolutely complete. But based on your knowledge of Python's numeric tower, I think you'd agree that this view, despite having been firmly held for centuries, isn't actually complete. ChrisA ___ 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/WEXGRVKZ7EOLM2D7EZZVS3EED7GBGGW2/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, Apr 15, 2022 at 11:12:26PM +1000, Chris Angelico wrote: > > If you look at languages that implement MI, and pick the implementations > > which allow it with the fewest restrictions, then that is "full MI". > > I'm with Greg on this one, for the simple reason that a future > language could have fewer restrictions than Python does, Not without making inheritance incoherent and inconsistent. E.g. in Python 2.2 and below, it was possible to design class hierarchies that resulted in methods being called twice or more times. Other signs of an incoherent MI model might include: * loops or cycles in your precedence graph; * superclasses being skipped; * inconsistent ordering (class A coming before class B for one method, but B before A for another method); * violating local precedence order, e.g. class Spam has A come before B, but in Spam's subclass the order flips to B before A; * or the order changes if you change the name of a class and nothing else about it. These are all Bad Things™ and Python avoids them all. You can only generalise MI up to a certain point, after which it becomes inconsistent and therefore buggy. That's why Python 2.2's MRO was dropped for the C3 linearization in 2.3: it was buggy. I'm assuming automatic conflict resolution. If its not automatic, it's not what I'm calling inheritance. If you have to manually specify which superclass to call, that's delegation. That's okay: inheritance is not the be all and end all of OOP. You can use delegation to solve problems too, or manual conflict resolution by renaming methods, as Eiffel does. And as I said before, it might be that the Eiffel or C++ model is *better* than Python's model. But given the assumptions that: - the inheritance model automatically resolves conflicts; - the MRO is entirely dependendent on the shape of the inheritance graph, and not on incidental properties like the name of classes; - the inheritance model is consistent, monotonic and preserves local precedence order (C3 linearization); then I believe that the Dylan/Python/Ruby/Perl/Raku MI model is as general as you can get, and models like Eiffel or C++ are more restrictive. I believe that you cannot drop any of those restrictions without the very idea of inheritance becoming incoherent. It is not a "No True Scotsman" fallacy. Other models of MI are legitimate even if they are not fully general. I have suggested that Python's fully generalised MI model may ultimately be worse than more restrictive models that provide less freedom to write unmaintainable code. I have repeatedly linked to the writing of Michele Simionato who explores these issues in excruciating detail. > and therefore > would become the only thing that offers "full MI", displacing other > languages. It's a meaningless concept, unless there is some form of > absolute completeness that can be attained Well duh Chris, sometimes I wonder if you read my posts before jumping in to disagree with me, that is *exactly* what I am arguing. If you exclude models of MI which are logically incoherent and inconsistent, (such as Python's prior to version 2.3), then Python's model of MI is objectively as complete as you can get. Whether I am right or wrong, this is an objective matter of fact, not a matter of taste or opinion, and it is certainly not a "No True Scotsman" value judgement against using more restrictive forms of MI. > My view: If a class inherits two parents, in any meaning of the word > "inherits" that follows the normal expectation that a subclass IS an > instance of its parent class(es), then it's MI. Inheritance and "is-a" relationships are independent. In some languages (but not Python), mixins provide inheritance but not an "is-a" relationship. In Python, virtual subclassing provides "is-a" without inheritance. -- Steve ___ 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/TEXBXLQ5HZFYDXO25YOGMQ7YHLS4JSQV/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, Apr 15, 2022 at 2:44 PM malmiteria wrote: > I got an idea that *should* allow for some (keyword : some) of the changes > i want without any breaks, i kinda wanna take the time to think about it, and > once i'm a bit more sure of it, i'll talk about it in details. Since you are thinking of ways that won't break current code, you might as well think of ways that won't need any syntax modification/adding extra features to the language. The current capabilities we get, including being able to customize the metaclass __getattribute__ method, might allow for that - and you'd have the advantage that your ideas could be immediately be made available in a pypi package. > > ___ 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/KAJEBWZRL2OMQ3GDRQG6XNENUXS7LLWU/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Chris Angelico writes: > I'm with Greg on this one, for the simple reason that a future > language could have fewer restrictions than Python does, and therefore > would become the only thing that offers "full MI", displacing other > languages. It's a meaningless concept, unless there is some form of > absolute completeness that can be attained (and if you go for that, NO > language offers "full MI"). > > My view: If a class inherits two parents, in any meaning of the word > "inherits" that follows the normal expectation that a subclass IS an > instance of its parent class(es), then it's MI. > > So if you have "class Foo(Spam, Ham):" and it is reasonable to treat a > Foo instance as if it were a Spam instance *and* reasonable to treat a > Foo instance as if it were a Ham instance, then it's MI. > > Erroring out when there is a conflict is a restriction, but I would > avoid the term "full MI" because it's more emotive than useful. I agree with you 100%. I think i would add that what should matter is that we can describe our experiences with accurate concepts, and not that we conduct ourselves based on the concepts we know. At least when talking about potential improvments. Sticking to the way its done "just" because it's the way it's done helps stabilising the language, but it makes it possible to miss improvements. Overall, if there's only valid reasons to implement a change, this change doesn't break anything and there's no valid reason not to implement it, and this change is not "full MI", fine, we're out of full MI, what's the big deal? (I'm not saying i'm talking about my proposal here...) I got an idea that *should* allow for some (keyword : some) of the changes i want without any breaks, i kinda wanna take the time to think about it, and once i'm a bit more sure of it, i'll talk about it in details. Someone mentionned the "class A(B(C)):" syntax was already meaning something, i've tried a few things, but overall, most scenarios simply fail with this syntax today. The only one i could make work was "class A(namedtuple(...not a class...)):" If anyone has any source / talks on that, i would love to read it. And if you have ever seen this kind of syntax used, let me know. Someone mentionned they had a hard time tracking my exact proposal, i'll give an up to date proposal at some point too, i'll try to keep it short this time. I also still need to do that survey to measure what peoples intuition are. ___ 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/LE5TNQDHVW5FXKRGXPCTQTKYIHSMRDHD/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Greg Ewing writes: > > malmiteria xD not malmalitia > Sorry! Should have gone to Specsavers... No worries :) ___ 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/PKPRE2OADUN7PUVYGYCQV27MIDWENXXP/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, 15 Apr 2022 at 20:40, Steven D'Aprano wrote: > > On Thu, Apr 14, 2022 at 10:46:46AM +1200, Greg Ewing wrote: > > On 13/04/22 8:29 am, Steven D'Aprano wrote: > > >>When multiple parent provide candidate to a method resolution, raise an > > >>error. > > > > > >Then you aren't doing full MI any more, > > > > That sounds like a "true Scotsman" argument. Who defines what > > "full MI" means? > > If you look at languages that implement MI, and pick the implementations > which allow it with the fewest restrictions, then that is "full MI". > I'm with Greg on this one, for the simple reason that a future language could have fewer restrictions than Python does, and therefore would become the only thing that offers "full MI", displacing other languages. It's a meaningless concept, unless there is some form of absolute completeness that can be attained (and if you go for that, NO language offers "full MI"). My view: If a class inherits two parents, in any meaning of the word "inherits" that follows the normal expectation that a subclass IS an instance of its parent class(es), then it's MI. So if you have "class Foo(Spam, Ham):" and it is reasonable to treat a Foo instance as if it were a Spam instance *and* reasonable to treat a Foo instance as if it were a Ham instance, then it's MI. Erroring out when there is a conflict is a restriction, but I would avoid the term "full MI" because it's more emotive than useful. ChrisA ___ 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/HRBMHDQSAAAWWXNBGMVXKIB34QHKYFBO/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Thu, Apr 14, 2022 at 10:46:46AM +1200, Greg Ewing wrote: > On 13/04/22 8:29 am, Steven D'Aprano wrote: > >>When multiple parent provide candidate to a method resolution, raise an > >>error. > > > >Then you aren't doing full MI any more, > > That sounds like a "true Scotsman" argument. Who defines what > "full MI" means? If you look at languages that implement MI, and pick the implementations which allow it with the fewest restrictions, then that is "full MI". Class parent/child relationships are not the same as biological relationships: https://www.youtube.com/watch?v=fWQ7TFFKEz8 so I hope that we can agree that excluding cycles and loops in your inheritance hierarchy is a necessary restriction, for our sanity if no other reason. I don't know of any languages that allow cycles in inheritance graphs. Beyond that, I believe that Python (and other languages) allow MI with the smallest set of restrictions, namely that there is a C3 linearization possible: https://en.wikipedia.org/wiki/C3_linearization I believe that those 3 requirements in C3 are the fewest restrictions while still having logically consistent behaviour. That's what I mean by "full MI". Of course languages can impose additional restrictions, e.g. that methods are independent, there there are no diamonds, etc. But they offer less than the full generality that Python (and other languages) offer. For instance, I believe that Eiffel allows MI with diamonds, so long as methods in different branches are independent. If two classes provide the same method, Eiffel raises an exception. (Michele Simionato calls this behaviour equivalent to traits.) That is *more restrictive* than Python, and so it offers *less* than a fully general model of MI. On the other hand, sometimes "less is more", and Michele has come to believe that Python's fully general MI is too powerful to be usable, and that more restrictive versions (traits) are better, or even avoiding inheritance in favour of generics, composition and delegation. We can implement mixins, or traits, or Eiffel-style inheritance, or whatever extra restrictions you want, using decorators or metaclasses. They don't need a change to the language definition of MI. > I can think of at least two languages that do something very > similar to what malmalitia is proposing: C++ and (if I remember > rightly) Eiffel. I don't think I've heard anyone claim that > C++ doesn't do "full MI". Oooh, ooh, let me sir! "C++ doesn't do full multiple inheritance." If you have to manually call a specific method, as shown here: https://devblogs.microsoft.com/oldnewthing/20210813-05/?p=105554 you're no longer using inheritance, you're doing delegation. I make no comment on whether C++ is justified on restricting inheritance in that way. Michele Simionato declares that C++ implements MI "badly", but I don't know his reason for that judgement. Multiple inheritance is complex. Managing that complexity is hard. It may be that that best way to manage it is to forgo the full generality of MI and all the complexity it brings, or by not using inheritance at all. But either way, Python currently offers MI in its full generality. Restricting it at the language level is a breaking change, and will not happen. -- Steve ___ 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/W3JF6YI45XROPERQOFZ24TMEZIOUNLAW/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 15/04/22 4:45 am, malmiteria wrote: malmiteria xD not malmalitia Sorry! Should have gone to Specsavers... -- Greg ___ 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/MWDXAJDS37HPCKKWX7FSCPJFS72SKPFM/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Greg Ewing writes: > That sounds like a "true Scotsman" argument. Who defines what > "full MI" means? +1 for the record, i consider it multiple inheritance as soon as one class can inherit from multiple parents, no matter anything else. > I can think of at least two languages that do something very > similar to what malmalitia is proposing malmiteria xD not malmalitia --- David Mertz, Ph.D. writes: > I also co-authored a widely read article on then-new C3 linearization in > Python with Michele Simianato before he wrote his really great explanation > of it in the Python docs, and his also great 15+ year old pieces on traits you mean this one? : https://www.python.org/download/releases/2.3/mro/ --- Steven d'Aprano writes: > Its not impossible, I have been telling you about traits since my > earliest posts in this thread. And traits aren't what i want. My proposal is very different from what i understand of trait so far. Although it's still new to me, so if you feel i'm missing something, feel free to explain it to me. > > Linearisation is litterally an operation that consist into converting > > a multiple inheritance tree into a simple inheritance tree. > > That is absolutely not what linearization does. That's very much what it does, implicitely tho. Take the mro from any class. create a copy of the first class, and assign it only one parent. This parent is the copy of the next in mro order, which too takes only one parent. until we reach the last one in mro order, which is object. This 100% simple inheritance tree behave as far as i can tell 100% like the original class. No matter if the original class was multiple inheritance or not. Resolution order is the exact same, super visiting order is the exact same... class.method calls are independant, so they wouldn't change either. this can't be done for every class very nicely, as editing __bases__ attribute sometime is not permitted. so you'll excuse me for not providing a nice bit of code that does the convertion in the inheritance tree for you. ___ 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/DZR7JHODTRAYYTWP6YH7E24ITC2ZEG36/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Thu, 14 Apr 2022 at 08:47, Greg Ewing wrote: > > On 13/04/22 8:29 am, Steven D'Aprano wrote: > >> When multiple parent provide candidate to a method resolution, raise an > >> error. > > > > Then you aren't doing full MI any more, > > That sounds like a "true Scotsman" argument. Who defines what > "full MI" means? I've come to accept that the term "Multiple Inheritance" has multiple meanings, all slightly different. They are related only in the sense that there are, in some way, multiple parent classes. The actual semantics vary from language to language in fairly vast ways (and sometimes multiple within the language - your example showed C++ with virtual subclassing, but if you remove the "virtual" keywords, it'll behave differently). While that doesn't mean different languages can't learn from each other, it most certainly does confuse the discussions. ChrisA ___ 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/7OHF4Y3NKR7EHCPBNTK7H2REXSDJJBIR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 13/04/22 8:29 am, Steven D'Aprano wrote: When multiple parent provide candidate to a method resolution, raise an error. Then you aren't doing full MI any more, That sounds like a "true Scotsman" argument. Who defines what "full MI" means? I can think of at least two languages that do something very similar to what malmalitia is proposing: C++ and (if I remember rightly) Eiffel. I don't think I've heard anyone claim that C++ doesn't do "full MI". Here's a C++ example: #include class A { public: void f() { printf("f in A\n"); } }; class B { public: void f() { printf("f in B\n"); } }; class AB: virtual A, virtual B { }; int main() { AB ab; ab.f(); } and compiling it gives this: mi.cpp:22:6: error: member 'f' found in multiple base classes of different types ab.f(); ^ mi.cpp:5:10: note: member found by ambiguous name lookup void f() { ^ mi.cpp:12:10: note: member found by ambiguous name lookup void f() { ^ 1 error generated. -- Greg just a limited, restricted version known as traits. The child class now has to redefine the method, and in the body of that method, can decide which parent method call, or in what order call them. That's essentially the basic idea of my proposal. What makes this impossible for you? Its not impossible, I have been telling you about traits since my earliest posts in this thread. Maybe you need to stop thinking you have invented some brilliant idea which has solved a problem nobody else has noticed, and read some of the Artima links I have days ago. I think i've adressed most if not all problems i had raised against it. Except the most important one: why are you using multiple inheritence when you clearly don't want multiple inheritence, instead you want delegation? Linearisation is litterally an operation that consist into converting a multiple inheritance tree into a simple inheritance tree. That is absolutely not what linearization does. That's bound to lose some info, No, the point of linearization is to avoid losing info. and can't cover all cases. Correct, there are inconsistent inheritence hierarchy which are impossible to linearise because they are inconsistent. It is better to get an error when you try to define the inconsistent hierarchy, rather than pretend it is consistent and then wonder why inheritence is not working and methods are called in inconsistent order. ___ 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/7RPZNLARFS5B6WXSQ5XIHMR2MPNO5UL5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 4/13/2022 7:22 AM, malmiteria wrote: Eric V. Smith writes: My suggestion is to rework your proposal to not break any existing code I've been doing that already, and i'll keep doing it, i'm very aware of this constraint. What are the biggest breaking change i haven't covered yet, in your opinion? If you can think of a few that seem way too bad please let me know. I'm not tracking your exact proposal very closely. The problem would be any code that uses existing syntax and raises the exception you're proposing when an attribute is defined in multiple base classes. I can't find the exact name you're proposing. I don't think we need to find existing code that meets this criteria. It doesn't matter if it requires diamond inheritance, non-diamond inheritance, or whatever. If the exception can possibly be raised in code that's valid in any currently supported python version, then you have a backward compatibility problem. Eric ___ 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/HTPXY2L6VVF63ZPGAY2XO3IZKB7VN76O/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 21:24, malmiteria wrote: > > Chris Angelico writes: > > A proposal that breaks existing code, and which introduces a new way > > to do things, will usually require multiple versions of deprecation > > time in order to be accepted. > Nothing is preventing us from doing that here. > I already intend to have the adoption syntax come first, since it doesn't > break anything pre existing, it can be added, and a few version later, the > breaking change can happen, you've got your deprecation time. > Your proposed syntax "class A(B(C)):" is currently valid syntax. You cannot claim that it "doesn't break anything". > > That usually means either a compatibility > > period, or a means of continuing to use the older syntax. > A compatibility period is probably the only way for the entire proposal, but > for most parts of it, i'm pretty sure it could be possible to have the older > syntax still apply. > Are you actually proposing to have two completely different class keywords? If not, what do you mean by "older syntax"? Be very clear. That said, though: I still think your proposal is solving a problem that is much MUCH better solved by ... not using inheritance. Class inheritance is NOT the same as biological parentage. But if you are going to make a proposal, be sure to acknowledge the breaking changes. ChrisA ___ 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/ZG2I5T5I53APVPBJIKWK7FGCEVGHXZUT/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Chris Angelico writes: > A proposal that breaks existing code, and which introduces a new way > to do things, will usually require multiple versions of deprecation > time in order to be accepted. Nothing is preventing us from doing that here. I already intend to have the adoption syntax come first, since it doesn't break anything pre existing, it can be added, and a few version later, the breaking change can happen, you've got your deprecation time. > That usually means either a compatibility > period, or a means of continuing to use the older syntax. A compatibility period is probably the only way for the entire proposal, but for most parts of it, i'm pretty sure it could be possible to have the older syntax still apply. > In the case of > the "except Exception, e:" syntax, the justification is that it is > confusingly similar to "except (Exception1, Exception2):" in a way > that causes hard-to-debug problems. I've already been over how MRO causes hard to debug problems, since it makes it possible for one class to ignore one of its parent attribute, while using the other parents attribute instead, without any warning / errors. Actually i got another exemple recently (at work, i wasn't really looking for it), on django doc : https://docs.djangoproject.com/fr/4.0/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin.get_test_func some classes dedicated to test some users all inherit from the same UserPassesTestMixin class. This class has some NotImplemented errors, in the method it provides to it's childrens. If we were to make multiple TestMixins, like described in the link i shared, calls to super aren't possible, and would lead to the mixins needing to be inherited all together. So there's no point writing down multiple of them, might aswell write down just one, and why would you, when you have multiple tests that have nothing to do with one another. The doc concludes it's impossible to use multiple TestMixins, and doesn't mention at all the class.method syntax that all of you seem to find so obvious. Given the popularity of django, it speaks volume to what i've been telling you for so long now. class.method syntax is *not* a solution, since it's very unlikely someone in need will find it. So there's very much a need to be covered here. > Don't simply dismiss the concern; > answer it by showing the need that justifies it. Hope it answers that remark. I'll still be working on that survey... it's taking me forever Will you have a read at the question before i run it, so you can agree before hand the questions are fair to you? --- Eric V. Smith writes: > I'm trying to > save you some time here, but if you're committed to continuing this, > then you can't say you weren't warned when it's ultimately rejected I'm aware of this, thanks for the warning nonetheless. > My > suggestion is to rework your proposal to not break any existing code I've been doing that already, and i'll keep doing it, i'm very aware of this constraint. What are the biggest breaking change i haven't covered yet, in your opinion? If you can think of a few that seem way too bad please let me know. ___ 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/KSH23FO6DLJJJV6DSNZBROS4C6RNQZII/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
> And, on top of that, the actual change needed to switch from today's solution to adoption is extremly simple. > replace > ``` > class A(B,C): ... > ``` > with > ``` > class A(B(C)): ... > ``` > That's it. `class A(B(C))` is already a valid Python syntax (for example you could use `class A(namedtuple(...))`), your change to add a specific meaning to this syntax would break existing code. Le mar. 12 avr. 2022 à 23:22, Eric V. Smith a écrit : > On 4/12/2022 12:57 PM, malmiteria wrote: > > So the amount of actual breakings left shouldn't be enough to justify > denying this feature IMO. Again, we'll have a clearer view on that once we > get experimental data. > > What's to look for is usage of super in MI cases, since each super call > in MI today should be replaced by one super call per parent, in my proposal. > > If this turns out to be an issue, we can try to imagine solution for it. > Maybe a solution such as : super calls implicitely run a super call to each > parent when there's multiple parent, and super isn't given arguments. This > i think would behave strictly as today's super + MRO, except for cases > where one class appears multiple time in an inheritance tree. > > The last breaking change would be that scenario, class appearing > multiple time in an inheritance tree. > > And we're getting on even rarer occasions here, but again, we can think > of solutions here. > > I have code in a non-public repository that your proposed change will > break. I'm sure I'm not the only one. It is not realistic to implement a > change like this that will break code and then say "there's a workaround > that you'll need to implement". Especially for library code that needs > to run across multiple python versions. > > > As much as i understand we don't want breaking change, i don't think it > is *that* strong an argument, in this case. > > And, on its own, breaking changes aren't a strict veto, there's been > some, and there's gonna be more. > > As a long-time core developer, I can assure you that this is one of > those cases where a breaking change will not be allowed. I'm trying to > save you some time here, but if you're committed to continuing this, > then you can't say you weren't warned when it's ultimately rejected. My > suggestion is to rework your proposal to not break any existing code. > It's a constraint we've all had to live with at one time or another, as > much as we don't like it. > > Eric > > ___ > 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/KWXDZBGZBX3LLCP3FQ33T27YUXDKXXL5/ > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Antoine Rozo ___ 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/XWL6V6ACH4M2OZTDBVZ5TY777IFB5I75/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 15:02, Ganesh B wrote: > > I hope nicer on the code text please. Sure. Sorry about that. malmiteria's "lib" code is ``` class HighGobelin: def scream(self): print("raAaaaAar") class CorruptedGobelin(HighGobelin): def scream(self): print("my corrupted soul makes me wanna scream") super().scream() class ProudGobelin(HighGobelin): def scream(self): print("I ... can't ... contain my scream!") super().scream() ``` Best regards, Takuo Matsuoka > > On Wed, Apr 13, 2022 at 9:21 AM Matsuoka Takuo wrote: >> >> On Wed, 13 Apr 2022 at 04:28, malmiteria wrote: >> > >> > Idk, what do you think? >> >> I would need to see more examples to determine the limit of the >> current strategy for method resolution and super. For the example at >> hand, I can be happy with the following code as a lib user (using your >> lib code). >> >> ``` >> class Proud_base(HighGobelin): >> scream = HighGobelin.scream >> >> class ProudGobelin_floating(ProudGobelin, Proud_base): >> pass >> >> class HalfBreed(ProudGobelin_floating, CorrupteGobelin): >> def scream(self): >> if random.choices([True, False]): >> super(HalfBreed, self).scream() >> else: >> super(Proud_base, self).scream() >> ``` >> >> Best regards, >> Takuo >> ___ >> 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/K63MS6XAS3OXGYDU4N47VIFMPNAWX2Z7/ >> Code of Conduct: http://python.org/psf/codeofconduct/ ___ 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/PX3LKNVFKHIE2MH7BYHC4JZT2E24TQQN/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 04:28, malmiteria wrote: > > Idk, what do you think? I would need to see more examples to determine the limit of the current strategy for method resolution and super. For the example at hand, I can be happy with the following code as a lib user (using your lib code). ``` class Proud_base(HighGobelin): scream = HighGobelin.scream class ProudGobelin_floating(ProudGobelin, Proud_base): pass class HalfBreed(ProudGobelin_floating, CorrupteGobelin): def scream(self): if random.choices([True, False]): super(HalfBreed, self).scream() else: super(Proud_base, self).scream() ``` Best regards, Takuo ___ 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/K63MS6XAS3OXGYDU4N47VIFMPNAWX2Z7/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 4/12/2022 12:57 PM, malmiteria wrote: So the amount of actual breakings left shouldn't be enough to justify denying this feature IMO. Again, we'll have a clearer view on that once we get experimental data. What's to look for is usage of super in MI cases, since each super call in MI today should be replaced by one super call per parent, in my proposal. If this turns out to be an issue, we can try to imagine solution for it. Maybe a solution such as : super calls implicitely run a super call to each parent when there's multiple parent, and super isn't given arguments. This i think would behave strictly as today's super + MRO, except for cases where one class appears multiple time in an inheritance tree. The last breaking change would be that scenario, class appearing multiple time in an inheritance tree. And we're getting on even rarer occasions here, but again, we can think of solutions here. I have code in a non-public repository that your proposed change will break. I'm sure I'm not the only one. It is not realistic to implement a change like this that will break code and then say "there's a workaround that you'll need to implement". Especially for library code that needs to run across multiple python versions. As much as i understand we don't want breaking change, i don't think it is *that* strong an argument, in this case. And, on its own, breaking changes aren't a strict veto, there's been some, and there's gonna be more. As a long-time core developer, I can assure you that this is one of those cases where a breaking change will not be allowed. I'm trying to save you some time here, but if you're committed to continuing this, then you can't say you weren't warned when it's ultimately rejected. My suggestion is to rework your proposal to not break any existing code. It's a constraint we've all had to live with at one time or another, as much as we don't like it. Eric ___ 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/KWXDZBGZBX3LLCP3FQ33T27YUXDKXXL5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Tue, Apr 12, 2022, 4:31 PM Steven D'Aprano > Except the most important one: why are you using multiple inheritence when > you clearly don't want multiple inheritence, instead you want delegation? > I'll note that hundreds of posts ago, I made the FIRST reply to this silliness, and that it 100% explained every single needless digression that followed: > If you want to explicitly delegate a method to a class, you should explicitly delegate a method to a class. > This is exactly why a lot of folks feel composition is better than inheritance (at least often so). > You don't need `super()` to call `SomeSpecificClass.method(self, other, args)` I also co-authored a widely read article on then-new C3 linearization in Python with Michele Simianato before he wrote his really great explanation of it in the Python docs, and his also great 15+ year old pieces on traits ___ 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/T3TAQ46HJ2LATLPYEP36LRLEZEA5YYCH/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 2022-04-12 11:02, malmiteria wrote: My proposal would completely detach method resolution from calls to super. essentially: ``` class A: val = 1 class B: val = 2 class C(A,B): pass C.val # raises an explicitness required error ``` If you think you can come up with code that would break under my proposal, hit me. I wanna have the least amount of breaking change. You just showed an example in your own message. The behavior of `C.val` is already defined in that case (it evaluates to 1). If you change it so it now raises an error, that's a breaking change. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown ___ 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/DE5NY7GLE6TPITTF7DW4ASQMKOSYT7JK/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Tue, Apr 12, 2022 at 11:17:27AM -, malmiteria wrote: > Steven D'Aprano writes: > > > So in the general case, order matters. We have to linearize the > > superclasses, and call them in that linear order, and the best way to do > > that is with the MRO and super. > Why would we *have* to do that? Because if you don't, you aren't doing multiple inheritence. If you don't want MI, if you want delegation or composition, then of course you can do something else. But if you want MI in its full generality, that's really the only thing you can do. > When multiple parent provide candidate to a method resolution, raise an error. Then you aren't doing full MI any more, just a limited, restricted version known as traits. > The child class now has to redefine the method, and in the body of that > method, can decide which parent method call, or in what order call them. > That's essentially the basic idea of my proposal. > What makes this impossible for you? Its not impossible, I have been telling you about traits since my earliest posts in this thread. Maybe you need to stop thinking you have invented some brilliant idea which has solved a problem nobody else has noticed, and read some of the Artima links I have days ago. > I think i've adressed most if not all problems i had raised against it. Except the most important one: why are you using multiple inheritence when you clearly don't want multiple inheritence, instead you want delegation? > Linearisation is litterally an operation that consist into converting > a multiple inheritance tree into a simple inheritance tree. That is absolutely not what linearization does. > That's bound to lose some info, No, the point of linearization is to avoid losing info. > and can't cover all cases. Correct, there are inconsistent inheritence hierarchy which are impossible to linearise because they are inconsistent. It is better to get an error when you try to define the inconsistent hierarchy, rather than pretend it is consistent and then wonder why inheritence is not working and methods are called in inconsistent order. -- Steve ___ 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/A3V2OYAD4USX64BAL7JMRDIFYUM2KLWD/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Eric V. Smith writes: > I've said this before, but I'll repeat it here: if your proposal is to > have super().something raise an error if "something" exists on more than > one parent class (via the MRO), then that's a breaking change and it > will not be accepted. The expliciteness required error should be raise at attribute / method access, not through super. My proposal would completely detach method resolution from calls to super. essentially: ``` class A: val = 1 class B: val = 2 class C(A,B): pass C.val # raises an explicitness required error ``` It's fair to assume super would need to know what parent class it should target however, especially since part of my proposal is to make it so that super can take as an argument the class it targets, instead of the previous in MRO order, but that is not something i consider an "active" part of my proposal (the idea that super needs to be passed a parent as argument in case of MI). As i was answering Ronald Oussoren, i figured that in case of MI, a call to super with no argument could simply loop over call to super with each parent, one after the other. That would keep it a nice way to tell "go fetch all parents behaviors" without having to write down one line per parent. I think it would behave 'strictly' as today's super calls, except in cases where one class appears multiple time in the inheritance tree (and is visited through calls to super). For those scenarios, i have a dedicated answer. Your exemple actually is one of those cases, since calls to super do visit the object parent class. Let's start with super() implicitelly calling super on all parents one after the other. ``` class A: def foo(self): print("A") try: super().foo() except AttributeError: print('no parent defines foo') class B: def foo(self): print("B") try: super().foo() except AttributeError: print('no parent defines foo') class C(A, B): def foo(self): print("C") super().foo() C().foo() ``` This would output (not accounting for the parent appearing multiple time proposal) : ``` C A no parent defines foo B no parent defines foo ``` in this case, C would be equivalent to, (but not require any rewrites): ``` class C(A, B): def foo(self): print("C") super(A, self).foo() super(B, self).foo() # keep in mind, in my proposal, the class passed as an argument is the one we target. ``` I occasionally write it down without the self, or with self.__as_parent__(..) but overall, i'm fine with super(class, self), as long as the class is the target, not the previous to the target in MRO order. You get the idea. If accounting for the parent appearing multiple time (i'll just call it the diamond case for now) my proposal for those is to have a module strats, that would allow to decide what occurence of a reoccuring parent should be visited or not. the default strat would be 'last', as to match the current behavior. Idk exactly what API is the better for this proposal, but since the goal is for it to default to today's behavior, we wouldn't need to write down anything related to it in this scenario, we would get that output ``` C A B no parent defines foo ``` Which is the one you want. TLDR: with my full proposal, the code you presented me won't break. It won't even change behavior at all. Or in other term, I acknowledge breaking changes are bad, but they're not impossible to cover for. And i think i have covered for it fairly extensively. If you think you can come up with code that would break under my proposal, hit me. I wanna have the least amount of breaking change. And as much as possible, i wanna cover for those breaking changes, to find a way to update my proposal, so those aren't breaking changes anymore. One thing i can think of rn is that calls to super in classes without parent would turn out to break with my proposal, since they would now refer to object anytime. That needs covering up too, and i'll be thinking on that one too. Like i've done for every scenario i've been opposed with so far, i think. ___ 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/SV4F7I2XNX3A2YCQ747TJW3XJF5CS2LF/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Tue, Apr 12, 2022 at 1:59 PM malmiteria wrote: > Ronald Oussoren writes: > > > To be blunt: That’s not going to happen because this is big backward > compatibility break. Either that, or this adds a > > second way to define classes. Both are good reasons to keep the status > quo. > > the breaking is limited MI with name collision, so likely rare enough, and > i've already mentionned that i'm perfectly willing to implement my proposal > and run it against whatever selection of python repos, to check for real > life exemple of breakings, so we can measure how bad it would actually be. > Sorry. I thought we were past this point and you had understood and agreed that any change in this respect would not change the current behavior of MRO and super, requiring either a different call than super, and/or a different metaclass for all the hierarchy, to start with. TL;DR: ***Changing the current behavior of super itself or the MRO formula is just not going to happen.*** And it is not me saying this. If you won't spare replying on the list, you can spare yourself from checking "whether this would break things". It would. But even if it does not break a particular project, that is not negotiable. And I am not saying that these changes,even as "add-ons" to the language are being considered either - IMHO you failed so far in presenting any evidence of your point or more people that would ask for the features you are proposing. The playful example you brought here with the Gobelin hierarchy, for example, could be addressed with a multitude of approaches, including custom-metaclases and even `__init_subclass__` methods, that would collect the methods with "name collision" and allow one to select a strategy when calling them. So, a custom base class or custom metaclass could attend your needs - and that does not need to live in the language core. > The most common case of breaking would be the django style mixins, which i > propose a dedicated feature for, adoption. > Essentially a way to declare more than your parent, but their parents too, > recursively. > would look like that: > ``` > class A(B(C)): ... > ``` > the adoption syntax is non breaking, as it's simply an addition to the > language, and has values on its own. > I'll make a dedicated post, but i'm a bit out of time for that now, > especially since i'm getting the survey ready. > I'll add some question to get infos that could help debate this feature > too, so i guess i'll wait for the survey result. > > Once adoption is ... adopted, and start getting used, the more it goes on, > the less breaking change will occur. > > And, on top of that, the actual change needed to switch from today's > solution to adoption is extremly simple. > replace > ``` > class A(B,C): ... > ``` > with > ``` > class A(B(C)): ... > ``` > That's it. > > So the amount of actual breakings left shouldn't be enough to justify > denying this feature IMO. Again, we'll have a clearer view on that once we > get experimental data. > What's to look for is usage of super in MI cases, since each super call in > MI today should be replaced by one super call per parent, in my proposal. > If this turns out to be an issue, we can try to imagine solution for it. > Maybe a solution such as : super calls implicitely run a super call to each > parent when there's multiple parent, and super isn't given arguments. This > i think would behave strictly as today's super + MRO, except for cases > where one class appears multiple time in an inheritance tree. > The last breaking change would be that scenario, class appearing multiple > time in an inheritance tree. > And we're getting on even rarer occasions here, but again, we can think of > solutions here. > > As much as i understand we don't want breaking change, i don't think it is > *that* strong an argument, in this case. > And, on its own, breaking changes aren't a strict veto, there's been some, > and there's gonna be more. > Overall, they are an upgrade cost we really wanna make as less expensive > as possible, but an worthwhile upgrade overcomes the upgrade costs. And, if > it improves something, the longer we wait, the more the current behavior > can deal its damage, it should be considered in the balance too. > Breaking changes are an momentary cost, while not upgrading might have a > smaller, but constant cost. > ___ > 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/LP22REU3YWWLRDOTKAZMTCC5EMHYP53A/ > Code of Conduct: http://python.org/psf/codeofconduct/ > ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org
[Python-ideas] Re: mro and super don't feel so pythonic
A general note on breaking changes: On Wed, 13 Apr 2022 at 03:01, malmiteria wrote: > > Ronald Oussoren writes: > > > To be blunt: That’s not going to happen because this is big backward > > compatibility break. Either that, or this adds a > > second way to define classes. Both are good reasons to keep the status quo. > > the breaking is limited MI with name collision, so likely rare enough, and > i've already mentionned that i'm perfectly willing to implement my proposal > and run it against whatever selection of python repos, to check for real life > exemple of breakings, so we can measure how bad it would actually be. > The most common case of breaking would be the django style mixins, which i > propose a dedicated feature for, adoption. > Essentially a way to declare more than your parent, but their parents too, > recursively. > would look like that: > ``` > class A(B(C)): ... > ``` > the adoption syntax is non breaking, as it's simply an addition to the > language, and has values on its own. > I'll make a dedicated post, but i'm a bit out of time for that now, > especially since i'm getting the survey ready. > I'll add some question to get infos that could help debate this feature too, > so i guess i'll wait for the survey result. > > Once adoption is ... adopted, and start getting used, the more it goes on, > the less breaking change will occur. > > And, on top of that, the actual change needed to switch from today's solution > to adoption is extremly simple. > replace > ``` > class A(B,C): ... > ``` > with > ``` > class A(B(C)): ... > ``` > That's it. This is a major problem for cross-version compatibility. If you make a breaking change in Python 3.42, the question must be: How should code be written that supports both 3.41 and 3.42? A breaking change that is supported by the older version is annoying, but can be acceptable if it's worth it. For example, this code works on Python 3.9, but not on Python 3.10: >>> import traceback >>> traceback.format_exception(etype=None, value=Exception(), tb=None) ['Exception\n'] But if this is a problem to your code, you can simply switch to positional arguments, and it will work on both versions: >>> traceback.format_exception(None, Exception(), None) ['Exception\n'] A proposal that breaks existing code, and which introduces a new way to do things, will usually require multiple versions of deprecation time in order to be accepted. Taking another example from exception handling, Python 2.5 and older use this syntax: try: spam() except Exception, e: print("Got an exception") print(e) Python 3.0 and later use this syntax: try: spam() except Exception as e: print("Got an exception") print(e) But in between, Python 2.6 and 2.7 are able to accept both forms. > As much as i understand we don't want breaking change, i don't think it is > *that* strong an argument, in this case. > And, on its own, breaking changes aren't a strict veto, there's been some, > and there's gonna be more. It is a VERY strong argument, but it can be answered by showing that the breakage can be managed. That usually means either a compatibility period, or a means of continuing to use the older syntax. > Overall, they are an upgrade cost we really wanna make as less expensive as > possible, but an worthwhile upgrade overcomes the upgrade costs. And, if it > improves something, the longer we wait, the more the current behavior can > deal its damage, it should be considered in the balance too. > Breaking changes are an momentary cost, while not upgrading might have a > smaller, but constant cost. > No, they are not a momentary cost; they are an ongoing cost for as long as any application or library needs to support both pre-change and post-change Python interpreters. Backward incompatibility demands a high justification. In the case of the "except Exception, e:" syntax, the justification is that it is confusingly similar to "except (Exception1, Exception2):" in a way that causes hard-to-debug problems. Don't simply dismiss the concern; answer it by showing the need that justifies it. ChrisA ___ 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/PE5P4FLYWC3B3D5RP7YCCMN5P7ZNNFXI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Matsuoka Takuo writes: > I don't think this is better than the failing code in any way. It > will fail in the same way. Yeah! i completely forgot that :p I've been redoing this exemple so many times now, it's hard to always keep the brain turned on when writing it. Thanks for pointing it out. > I think she should have done as follows, and > that's close to the solution I shared with you first. I understand that this solution works, as in, it provides a way for the lib user's to make HalfBreed work as intended. But i think that it requires way too much efforts, and essentially hints at a flaw of today's design. With my proposal, you wouldn't have to change the lib at all: ``` class HighGobelin: def scream(self): print("raAaaaAar") class CorruptedGobelin(HighGobelin): def scream(self): print("my corrupted soul makes me wanna scream") super().scream() class ProudGobelin(HighGobelin): def scream(self): print("I ... can't ... contain my scream!") super().scream() ``` would be enough. A lib user could write : ``` class HalfBreed(ProudGobelin, CorruptedGobelin): def scream(self): if random.choice([True, False]): super(ProudGobelin, self).scream() # OR : super(ProudGobelin).scream() # OR : self.__as_parent__(ProudGobelin).scream(), in the toy implementation i made here : https://github.com/malmiteria/super-alternative-to-super/blob/master/parent.py else: super(CorruptedGobelin, self).scream() ``` This would work like intended. Of course the question now is, how do we limit the breaking changes, and how to we leave open the option to have a class appearing multiple time in an inheritance tree called only once through super, as it is today's behavior, and is sometimes what we want. That's what i'm most unclear on, maybe we could have a class attribute, or a method decorator. Maybe we could add an argument to super, idk. The point would be to be able to specify somewhere the strategy we wanna use for parent appearing multiple times. maybe something like that would work fine: ``` import strat class HalfBreed(ProudGobelin, CorruptedGobelin): __visit_reoccuring_parents__ = strat.last def scream(self): ... (same as before) ``` or ``` import strat class HalfBreed(ProudGobelin, CorruptedGobelin): @visit_reoccuring_parents(strat.last) def scream(self): ... (same as before) ``` where available strats would be "last", "all", and maybe "only_after", where we would be able to specify which occurence should be visited. the decorator allows a method specific selection, the class attribute doesn't, so maybe the decorator is better. Idk, what do you think? Overall what matters to me is that we can chose the strat in case a parent appears multiple time in an inheritance tree, and that we can set the default strat to match today's strat. The implementation details, and overall API, i don't know exactly what they should look like. ___ 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/BDKMW6ICH47WQONXXNZQBCHKPSA2BBGR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Ronald Oussoren writes: > To be blunt: That’s not going to happen because this is big backward > compatibility break. Either that, or this adds a > second way to define classes. Both are good reasons to keep the status quo. the breaking is limited MI with name collision, so likely rare enough, and i've already mentionned that i'm perfectly willing to implement my proposal and run it against whatever selection of python repos, to check for real life exemple of breakings, so we can measure how bad it would actually be. The most common case of breaking would be the django style mixins, which i propose a dedicated feature for, adoption. Essentially a way to declare more than your parent, but their parents too, recursively. would look like that: ``` class A(B(C)): ... ``` the adoption syntax is non breaking, as it's simply an addition to the language, and has values on its own. I'll make a dedicated post, but i'm a bit out of time for that now, especially since i'm getting the survey ready. I'll add some question to get infos that could help debate this feature too, so i guess i'll wait for the survey result. Once adoption is ... adopted, and start getting used, the more it goes on, the less breaking change will occur. And, on top of that, the actual change needed to switch from today's solution to adoption is extremly simple. replace ``` class A(B,C): ... ``` with ``` class A(B(C)): ... ``` That's it. So the amount of actual breakings left shouldn't be enough to justify denying this feature IMO. Again, we'll have a clearer view on that once we get experimental data. What's to look for is usage of super in MI cases, since each super call in MI today should be replaced by one super call per parent, in my proposal. If this turns out to be an issue, we can try to imagine solution for it. Maybe a solution such as : super calls implicitely run a super call to each parent when there's multiple parent, and super isn't given arguments. This i think would behave strictly as today's super + MRO, except for cases where one class appears multiple time in an inheritance tree. The last breaking change would be that scenario, class appearing multiple time in an inheritance tree. And we're getting on even rarer occasions here, but again, we can think of solutions here. As much as i understand we don't want breaking change, i don't think it is *that* strong an argument, in this case. And, on its own, breaking changes aren't a strict veto, there's been some, and there's gonna be more. Overall, they are an upgrade cost we really wanna make as less expensive as possible, but an worthwhile upgrade overcomes the upgrade costs. And, if it improves something, the longer we wait, the more the current behavior can deal its damage, it should be considered in the balance too. Breaking changes are an momentary cost, while not upgrading might have a smaller, but constant cost. ___ 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/LP22REU3YWWLRDOTKAZMTCC5EMHYP53A/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 02:00, Matsuoka Takuo wrote: > > Thanks for your answer. > > On Mon, 11 Apr 2022 at 00:46, malmiteria wrote: > > > > There's a few problems, mainly, if you provide ProudGobelin and > > CorruptedGobelin as a lib author, you're very likely not to think of the > > HalfBreed use case, so the lib users wanting to create the HalfBreed class > > is bared from this solution, as it requires some work on ProudGobelin and > > CorruptedGobelin classes. Actually, now I see. It's the lib author's fault. She went against DRY in defining CorruptedGobelin and ProudGobelin as unrelated subclasses of HighGobelin when they had a common structure, unless she intended to make things like the "failing" version of HalfBreed easier to create. Otherwise, I think she should have done as follows, and that's close to the solution I shared with you first. ``` class HighGobelin: def scream(self): print("raAaaaAar") class SpeakingGobelin(HighGobelin): def scream(self): self._speak() super().scream() def _speak(self): return class CorruptedGobelin(SpeakingGobelin): def _speak(self): print("my corrupted soul makes me wanna scream") class ProudGobelin(SpeakingGobelin): def _speak(self): print("I ... can't ... contain my scream!") ``` Best regards, Takuo ___ 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/KTXAPEKGLCP5LS3FJYQXBZIF7ZM5AERI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 4/12/2022 7:43 AM, malmiteria wrote: Brendan Barnwell writes: You seem to be envisioning a system in which multiple inheritance gives a subclass a "menu" of behaviors from which it may explicitly choose, but does not actually combine the superclasses' behaviors into a single, definite behavior of the subclass. In that scheme, order of multiple inheritance would not matter, because the superclasses don't need to be "integrated" into the subclass; they just sit there waiting for the subclass to explicitly decide which superclass it wants to delegate to. not sure i had time to answer this one yet, so here we are. I do not want any change in case of simple inheritance, nor do i want any change in case of MI where there's no name collision. The integration of parent class would be the exact same in those cases. And if you doubt it, my proposal, about method resolution, is that if there's only one candidate for resolution, we select it, if there's none, we raise the standard attribute error, and if there's multiple, we raise an explicitness required error. In case of MI where there's no name collision, aka, there's never more than one candidate for resolution, the behavior would be the exact same. Expliciteness is required only in case there's multiple candidates for resolution. I've said this before, but I'll repeat it here: if your proposal is to have super().something raise an error if "something" exists on more than one parent class (via the MRO), then that's a breaking change and it will not be accepted. This code: ``` class A: def foo(self): print("A") try: super().foo() except AttributeError: print('no parent defines foo') class B: def foo(self): print("B") try: super().foo() except AttributeError: print('no parent defines foo') class C(A, B): def foo(self): print("C") super().foo() C().foo() ``` Must continue to output: ``` C A B no parent defines foo ``` Eric ___ 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/RM4HPZV7MAQTKDMEDZSVAD7K2JIPKMXI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
> On 12 Apr 2022, at 13:17, malmiteria wrote: > > Steven D'Aprano writes: > >> So in the general case, order matters. We have to linearize the >> superclasses, and call them in that linear order, and the best way to do >> that is with the MRO and super. > Why would we *have* to do that? > When multiple parent provide candidate to a method resolution, raise an error. > The child class now has to redefine the method, and in the body of that > method, can decide which parent method call, or in what order call them. > That's essentially the basic idea of my proposal. To be blunt: That’s not going to happen because this is big backward compatibility break. Either that, or this adds a second way to define classes. Both are good reasons to keep the status quo. You’re of course free to create a library that checks for this at runtime, or as a lint tool. Ronald — Twitter / micro.blog: @ronaldoussoren Blog: https://blog.ronaldoussoren.net/ ___ 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/K4L3SQGKZX2IUKXTSJQLYO53WIQZJJZB/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Thanks for your answer. On Mon, 11 Apr 2022 at 00:46, malmiteria wrote: > > There's a few problems, mainly, if you provide ProudGobelin and > CorruptedGobelin as a lib author, you're very likely not to think of the > HalfBreed use case, so the lib users wanting to create the HalfBreed class is > bared from this solution, as it requires some work on ProudGobelin and > CorruptedGobelin classes. Starting from the "lib" definitions of HighGobelin, CorruptedGobelin and ProudGobelin you originally wrote, the lib user can surely have a similar solution, but, it will take many more (though straightforward) steps. So, if the lib code was that, MRO doesn't seem to be the most helpful thing for the lib user. (I assume, with your solution, the other behaviour of HalfBreed, that is, the original behaviour of it with the "failing" code, can also be achieved as easily in the case where that is what the lib user wants. Does this hold?) By the way, On Mon, 4 Apr 2022 at 02:11, malmiteria wrote: > > Getting the correct behavior requires to let go of super, in such a way: > > > ``` > class HalfBreed(ProudGobelin, CorrupteGobelin): > def scream(self): > if random.choices([True, False]): > ProudGobelin.scream(self) > else: > CorrupteGobelin.scream(self) > ``` I don't think this is better than the failing code in any way. It will fail in the same way. If you stopped using super in ProudGobelin.scream, then you would have been good, even though that's not necessary as I already said. The lib user can't complain the use of super when it does the job for the lib author, but what I felt from the example is there might be some notion of abuse of super, perhaps. Best regards, Takuo Matsuoka ___ 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/L5CEOFISOPJDMPUPE6KQDT7OBDT3LPQ5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > Do you think that the order of arguments in func(a, b) doesn't matter? Actually it doesn't: ``` def func(a, b): print(a) print(b) func(b=10, a=5) ``` would print 5, then 10 But i get what you mean, and i know very much it matters here. > One of the reasons why this discussion isn't going anywhere is that we > agree that MI is difficult, but your "solution" to that is to make > super() even more complex, with even more to learn, so that people can > use MI in even more cases of problems which are better solved with > another technique. I disagree, assuming all my proposal passes, super would be completely untied from MRO, which is the toughest nut to crack, it would allow to target the class you pass as an argument, which makes it much more straightforward to use than today. If we only add a kwarg target to super for example, then maybe it complexifies the design of super, but not it's uses. They would be able to use it in more cases, sure, but the actual uses cases of today would also be easier to deal with. if today some cases are hard to solve with MI, and tomorrow those same cases are hard to solve with MI, but the other cases got simpler, isn't that an improvment? perhaps it's way to abstract now, would we benefit in this discussion from having some toy implementation of it so we could compare before / after? > It is like you only have one tool in your toolbox, super, and you want > to solve every problem with it. It's more like you're given only one tool, and you realise it doesn't work well. But not everyone knows where to look for better tools. And we're here to design the toolbox, so let's adress this problem. ___ 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/2VMDN7ISEXP7ARHZ6B3V25SBS36WTEXI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Brendan Barnwell writes: > You seem to be envisioning a system in which multiple inheritance > gives a subclass a "menu" of behaviors from which it may explicitly choose, > but does not actually combine the superclasses' behaviors into a single, > definite behavior of the subclass. In that scheme, order of multiple > inheritance would not matter, because the superclasses don't need to be > "integrated" into the subclass; they just sit there waiting for the > subclass to explicitly decide which superclass it wants to delegate to. not sure i had time to answer this one yet, so here we are. I do not want any change in case of simple inheritance, nor do i want any change in case of MI where there's no name collision. The integration of parent class would be the exact same in those cases. And if you doubt it, my proposal, about method resolution, is that if there's only one candidate for resolution, we select it, if there's none, we raise the standard attribute error, and if there's multiple, we raise an explicitness required error. In case of MI where there's no name collision, aka, there's never more than one candidate for resolution, the behavior would be the exact same. Expliciteness is required only in case there's multiple candidates for resolution. Also, super, or the equivalent i named __as_parent__ in my poc, would be able to target the parent class it's given as an argument, as well as implicitely chose the only parent, when there's only one parent. Order of the parent doesn't matter, because we just don't need it anymore. Not because we're not integrating the parents. > they just sit there waiting for the > subclass to explicitly decide which superclass it wants to delegate to. Implicitness would still be the overall norm. > When a subclass inherits from multiple superclasses, the > superclass behaviors are *combined* into a *single* set of behaviors for > the subclass. They're not "held separate" somehow as alternative > inheritance hierarchies; they are joined into one. Demonstrably false: ``` class Dad: age = 65 class Mom: age = 61 class Son(Dad, Mom): pass ``` Son.age is definitely not a combination of Dad's and Mom's age Same apply for methods, they only "combine" assuming Dad's method calls super. Which it's likely not to if it's meant to run independant instances, as it doesn't have parent itself. But it is possible to have those behavior combine, yeah. > They're not "held separate" somehow as alternative > inheritance hierarchies; they are joined into one. All but one are ignored, and that one has the responsibility to care about the others. The design i propose would make the responsibility of "caring" about all its parent to the class inheriting from them. Which localises the responsibility a bit better i think, and definitely allows for actual integration of multiple class into one, at least as well as today's solution. There's probably a joke about parents ignoring conflict so much it leads to divorce somewhere in there. > I don't want to sound harsh, but if `class A(B, > C)` doesn't "feel" different to you from `class(C, B)` then I think you > need to adjust your feelings rather than expect Python to adjust its > behavior. You're absolutely not harsh, you're actually quite respectful. Disagrement is not an insult. I think that python is (at least know to be) a language that cares about making it the easiest to program. Or that it's made to be easy to learn. Essentially, that it always cared about having a very reliable UX design, not that it named it UX design, but that's at the core of python values. I believe the change i propose goes very well with those values / goals of python, and wouldn't be out of place in python. I don't believe it's as clear cut as you say it is, honestly. As much as i understand the feeling 'perhaps its time you learn', i don't believe it applies here, since it's a commonly misunderstood feature. If i were the actual only one guy who didn't understand it, sure. But that's not the case. And at some point, we gotta look at the feature itself. ___ 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/G7EEFAWMODTAUZKW63VRJANEG2CU5B7B/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > So in the general case, order matters. We have to linearize the > superclasses, and call them in that linear order, and the best way to do > that is with the MRO and super. Why would we *have* to do that? When multiple parent provide candidate to a method resolution, raise an error. The child class now has to redefine the method, and in the body of that method, can decide which parent method call, or in what order call them. That's essentially the basic idea of my proposal. What makes this impossible for you? I think i've adressed most if not all problems i had raised against it. This gives much more power to python users, clarifies possible missed name collisions and changes absolutely nothing on SI. And why do you say MRO and super is the best way to do that? If you mean it's the best way to do linearisation fine, but if you're saying it's the best way to do method / attribute resolution, i disagree. Linearisation is litterally an operation that consist into converting a multiple inheritance tree into a simple inheritance tree. That's bound to lose some info, and can't cover all cases. ___ 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/QESYIA72COVSP4YIJEZJH6SJMALV566U/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > In any case, how do you know what "most people" think? Have you done a > survey, or are you just guessing? I haven't done a survey, but I'm getting one ready, I also wanna let you all have a read at it before running it, so we can all agree the data we would get from it are meaningful, if that's okay with you. I am not guessing either however, knowledge is formed in a somewhat deterministic way, and UX design to some extent plays a role in it. You are very likely to form knowledge coherent with what you experience, and the most experience in case of use of super is simple inheritance, which means you're likely to learn a lot about super and SI before you face a MI case, in which, you'd have only the SI experience to build off of an expectation. > Actually, we are defining arguments to be passed: the listed > superclasses are passed on to the class metaclass as a tuple, which > preserves order, and the MRO is generated from that ordered tuple. Same problem as before, this is definitely not obvious to most python users, they never have to dive in those metaclasses logics, and therefore, it can't play a role in their understanding of what's happening at class definition. So again, the most common intuition on what happens at class definition would would be very different from the most common intuition about method definition / calls. Essentially, I'm saying that most people intuition is something, and you're answering that this thing almost no one knows about shows otherwise. It doesn't, since they don't know about it. You get my point. ___ 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/NH57FNMP3WS3PDS32GJPGKT7ICC53WFQ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Mon, Apr 11, 2022 at 3:39 AM Chris Angelico wrote: On Mon, 11 Apr 2022 at 15:25, Stephen J. Turnbull > wrote: > > [1] They don't have to be big problems or proprietary code; computing > > Fibonacci sequences will do, if you can find a way to make MI relevant > > to that task. > > > > > We shall now hold a funeral for the brain cells lost by everyone who > just read that code. > Fortunately, I was still through my Monday morning cup of coffee - it took most of the damage. ___ 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/FMDT6JFLBN5SHOC6DLMUMAMG4AXCTXRQ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sun, Apr 10, 2022 at 11:50:40AM -0700, Brendan Barnwell wrote: > You seem to be envisioning a system in which multiple inheritance > gives a subclass a "menu" of behaviors from which it may explicitly > choose, > but does not actually combine the superclasses' behaviors into a single, > definite behavior of the subclass. In that scheme, order of multiple > inheritance would not matter, because the superclasses don't need to be > "integrated" into the subclass; they just sit there waiting for the > subclass to explicitly decide which superclass it wants to delegate to. Thanks Brendan, that has helped me understand where malmiteria is coming from. I think that your comments explains a lot of his ideas about MI. > Maybe that's how MI works in some other languages, but not Python. > Everything about a class --- super, MRO, everything --- is impacted by > its ENTIRE superclass hierarchy, including the order in which classes > are inherited. When a subclass inherits from multiple superclasses, the > superclass behaviors are *combined* into a *single* set of behaviors for > the subclass. They're not "held separate" somehow as alternative > inheritance hierarchies; they are joined into one. +1 > Likewise, the order in which a class inherits multiple superclasses > matters in Python. That's just how Python works, and there's no way > that's going to change. I don't want to sound harsh, but if `class A(B, > C)` doesn't "feel" different to you from `class(C, B)` then I think you > need to adjust your feelings rather than expect Python to adjust its > behavior. And +1 to that too. -- Steve ___ 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/Q7PLWUGJLWVDEFOGX6AMEBSKK3AGACRT/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Mon, 11 Apr 2022 at 15:25, Stephen J. Turnbull wrote: > [1] They don't have to be big problems or proprietary code; computing > Fibonacci sequences will do, if you can find a way to make MI relevant > to that task. > Okay, I'll bite. Unfortunately for the OP, super() works perfectly here. class Fibo0: def get(self): return 0 def make_fibo(n): if n <= 0: return Fibo0 if n <= 2: class Fibo(Fibo0): def get(self): return super().get() + 1 return Fibo class Fibo(make_fibo(n - 1), make_fibo(n - 2)): pass return Fibo for i in range(17): print(i, make_fibo(i)().get()) We shall now hold a funeral for the brain cells lost by everyone who just read that code. ChrisA PS. If you're surprised by the range(17) there, try range(18) and you'll see how horrific this code is. ___ 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/HTMMGRXEZAVLRDPYNSFOMFTNIMZUJ7WG/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
malmiteria writes: > You'd need to return A.bar in C bar methods to get more symmetry, > but what if you wanted foo to visit the inheritance tree in this > order? I don't want that, however. Please give up this notion that you can tell anybody else what they might want. You need to show how that alternative mro is useful, and for some purpose other than arguing against the current design of super. I wrote a lot more, but I need to cool down before sending it, if at all. But here's the general problem with all of your "what ifs": Multiple inheritance is not a general specific, it does not solve all problems. "Some people, when faced with a problem, immediately think: 'I know, I'll use multiple inheritance!' Now they have multiple problems." If multiple inheritance causes you problems, maybe it's absolutely the wrong design pattern for your program. So *you* need to show us examples of real code for real problems[1] where there's a clear use for multiple inheritance (or at least an API which documents that one right way to use it is multiple inheritance) and still super() with the C3 mro messes you up. Footnotes: [1] They don't have to be big problems or proprietary code; computing Fibonacci sequences will do, if you can find a way to make MI relevant to that task. ___ 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/K2FYPXQEX4YAXNBXAKKRHJQSHV47RU7Q/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sun, Apr 10, 2022 at 05:56:14PM -, malmiteria wrote: > No, i'm arguing that MI is intuitively different enough from other > context in which we use parenthesis so that most people will > intuitively understand it to work differently (which it does, we're > not defining argument to be passed when called here), and essentially, > to mean something completely unrelated. Actually, we are defining arguments to be passed: the listed superclasses are passed on to the class metaclass as a tuple, which preserves order, and the MRO is generated from that ordered tuple. So your intuition about superclasses is wrong. In any case, how do you know what "most people" think? Have you done a survey, or are you just guessing? -- Steve ___ 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/RI3B556TJKU4H3C4VXOIUUL3JCLAOGIK/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
David, when you exaggerate the strength of your argument, you make all of us look bad. Like this: > Can you think of ANY context in Python in which the order of items in > parentheses isn't important?! Sure: operator.add(1, 2) == operator.add(2, 1) For that matter, there are plenty of mixins where class C(A, B) class C(B, A) *are* equivalent. It is just that in general they aren't. We had a reasonable argument, that in general the order of arguments matter. But by asking for *even one single counter-example*, or in your words "ANY", you undercut that message. In any case, I think this discussion about the order of declaration for superclasses is a distraction. How else are we going to declare superclasses except in a sequence, left to right? And the order of inheritance does matter in general. It makes a difference whether you call the superclass methods in this order: A.method() # copy data from temporary files to the database B.method() # delete temporary files or in this order: B.method() # delete temporary files A.method() # copy data from temporary files to the database So in the general case, order matters. We have to linearize the superclasses, and call them in that linear order, and the best way to do that is with the MRO and super. -- Steve ___ 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/KMVPCXT34UZLTR3M7BRLIQEHWKREA3DO/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sun, Apr 10, 2022 at 03:50:48PM -, malmiteria wrote: > Steven D'Aprano writes: > The order in which parents are placed in case of multiple inheritance > is far from being that obviously assymetrical, and the syntax does not > hint it is, quite less than inheritance syntax. Do you think that the order of arguments in func(a, b) doesn't matter? > "class A(B)" feels very different from "class B(A)" > but "class A(B,C)" doesn't feel so obviously different from "class A(C,B)" > Despite it mattering the exact same amount. > > That's an UX problem, essentially. > It is not so obvious the order matter in MI. No, it is an education problem. Programming is a complex task that requires both skill and knowledge that must be learned, and that includes the fact that the order of arguments to functions, the order of operands to some operators (subtraction, division, power) and the order of superclasses do matter. One of the reasons why this discussion isn't going anywhere is that we agree that MI is difficult, but your "solution" to that is to make super() even more complex, with even more to learn, so that people can use MI in even more cases of problems which are better solved with another technique. It is like you only have one tool in your toolbox, super, and you want to solve every problem with it. "This screwdriver is not very good at hammering nails, so we should give it a much harder, heavier handle, so we can hammer nails better." -- Steve ___ 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/IJTIT3UCGCST5W6QLT5GPXE6QGP6MTQQ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 2022-04-10 08:50, malmiteria wrote: The order of inheritance as in, one class inherits from another do matter, quite obviously, since it's not a symetrical operation, and accordingly, the syntax is not symettrical. The order in which parents are placed in case of multiple inheritance is far from being that obviously assymetrical, and the syntax does not hint it is, quite less than inheritance syntax. IE: "class A(B)" feels very different from "class B(A)" but "class A(B,C)" doesn't feel so obviously different from "class A(C,B)" Despite it mattering the exact same amount. I'm not the first person to say this, but your example here again makes clear to me that your real issue has nothing to do with super or MRO. Your problem is with multiple inheritance at a conceptual level. You seem to be envisioning a system in which multiple inheritance gives a subclass a "menu" of behaviors from which it may explicitly choose, but does not actually combine the superclasses' behaviors into a single, definite behavior of the subclass. In that scheme, order of multiple inheritance would not matter, because the superclasses don't need to be "integrated" into the subclass; they just sit there waiting for the subclass to explicitly decide which superclass it wants to delegate to. Maybe that's how MI works in some other languages, but not Python. Everything about a class --- super, MRO, everything --- is impacted by its ENTIRE superclass hierarchy, including the order in which classes are inherited. When a subclass inherits from multiple superclasses, the superclass behaviors are *combined* into a *single* set of behaviors for the subclass. They're not "held separate" somehow as alternative inheritance hierarchies; they are joined into one. Likewise, the order in which a class inherits multiple superclasses matters in Python. That's just how Python works, and there's no way that's going to change. I don't want to sound harsh, but if `class A(B, C)` doesn't "feel" different to you from `class(C, B)` then I think you need to adjust your feelings rather than expect Python to adjust its behavior. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown ___ 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/4PF5PQAV2RXLZVRH4LDQHC5VXK4VSVDP/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Mon, 11 Apr 2022 at 03:57, malmiteria wrote: > > David Mertz, Ph.D. writes: > > Can you think of ANY context in Python in which the order of items in > > parentheses isn't important?! > kwargs > Since Python 3.6, order of kwargs is preserved, and some functions do care about it (although only in minor ways, like the display order of attributes). ChrisA ___ 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/EBJARDGYVZTIMIVMH5543YZOUMN7VQBD/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
David Mertz, Ph.D. writes: > Can you think of ANY context in Python in which the order of items in > parentheses isn't important?! kwargs > You are arguing that defining inheritance order is "intuitively" the one > and only context in which the order of items in parentheses makes no > difference. No, i'm arguing that MI is intuitively different enough from other context in which we use parenthesis so that most people will intuitively understand it to work differently (which it does, we're not defining argument to be passed when called here), and essentially, to mean something completely unrelated. Most people wouldn't see it as related at all with other use case of parenthesis, and wouldn't compare 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/WIKLS34UZHUY6GRLJYV5JLBKDEGDJL62/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Can you think of ANY context in Python in which the order of items in parentheses isn't important?! (a, b, c) != (c, b, a) func(a, b, c) != func(c, b, a) etc. You are arguing that defining inheritance order is "intuitively" the one and only context in which the order of items in parentheses makes no difference. On Sun, Apr 10, 2022, 1:23 PM malmiteria wrote: > David Mertz, Ph.D. writes: > > Are you likewise "confused" by the fact that `a = b - c` is generally > > different from `a = c - b`?! > > Why do you always quote confused? > > I'm not, but that's because i've been taught / i've experienced that since > primary school. I have been taught math, but not python, nor any programing > language. > > Most people experience with python will lead them to understand easily > that parenthesis are definitely not symetrical, since calling a function is > a common thing to do in python, and most programming language. > As much as they would be able to understand that there is many different > context in which what's define inside the parenthesis doesn't always mean > the same thing. And overall, the "parenthesis operation" doesn't exists as > one simple thing. > Sure there's __call__, but parenthesis are also used in method definition, > method call and class definition, on top of class calls. > As much as there is some importance of the order of the arguments in > method definition, it's definitely a fair assumption, based on generic > experiences with the language, that parenthesis in the syntax "class A(B)" > simply means something different, and is a different operation. > > However, the class definition allows you to refer the class by the name > placed before the parenthesis, so it's obvious even only with a generic > python experience that the "inside/outside" parenthesis order matter. > Much more than the order within the parenthesis. > ___ > 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/43AEEIGIBPFEPKAIZWPN34PCVGR4QWBD/ > Code of Conduct: http://python.org/psf/codeofconduct/ > ___ 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/V4VEYL4OJBYAJZLMI4DKWWWPSWNEMSZM/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
David Mertz, Ph.D. writes: > Are you likewise "confused" by the fact that `a = b - c` is generally > different from `a = c - b`?! Why do you always quote confused? I'm not, but that's because i've been taught / i've experienced that since primary school. I have been taught math, but not python, nor any programing language. Most people experience with python will lead them to understand easily that parenthesis are definitely not symetrical, since calling a function is a common thing to do in python, and most programming language. As much as they would be able to understand that there is many different context in which what's define inside the parenthesis doesn't always mean the same thing. And overall, the "parenthesis operation" doesn't exists as one simple thing. Sure there's __call__, but parenthesis are also used in method definition, method call and class definition, on top of class calls. As much as there is some importance of the order of the arguments in method definition, it's definitely a fair assumption, based on generic experiences with the language, that parenthesis in the syntax "class A(B)" simply means something different, and is a different operation. However, the class definition allows you to refer the class by the name placed before the parenthesis, so it's obvious even only with a generic python experience that the "inside/outside" parenthesis order matter. Much more than the order within the parenthesis. ___ 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/43AEEIGIBPFEPKAIZWPN34PCVGR4QWBD/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sun, Apr 10, 2022, 11:51 AM malmiteria > "class A(B)" feels very different from "class B(A)" > but "class A(B,C)" doesn't feel so obviously different from "class A(C,B)" > Are you likewise "confused" by the fact that `a = b - c` is generally different from `a = c - b`?! > ___ 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/7DC66QOXIKRCXM7EJ522HUMCIDIVCVK5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > Yes well that was just silly. Of course the order matters. The order of inheritance as in, one class inherits from another do matter, quite obviously, since it's not a symetrical operation, and accordingly, the syntax is not symettrical. The order in which parents are placed in case of multiple inheritance is far from being that obviously assymetrical, and the syntax does not hint it is, quite less than inheritance syntax. IE: "class A(B)" feels very different from "class B(A)" but "class A(B,C)" doesn't feel so obviously different from "class A(C,B)" Despite it mattering the exact same amount. That's an UX problem, essentially. It is not so obvious the order matter in MI. ___ 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/OJSTZ25CS2TELKIR2O7FUKHSKQG3M2FO/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sun, Apr 10, 2022, 10:35 AM Steven D'Aprano > I don't believe that David's denials that people are confused by super() > are even a little bit reasonable. I take the words "unconcerned" and "confused" to be distinct. ___ 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/IPIWPFOHRYJ2S6KKJ5C6P52JOLKPARFN/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Mon, 11 Apr 2022 at 00:35, Steven D'Aprano wrote: > Yes well that was just silly. Of course the order matters. > > Even in single inheritance, the order matters: > > Spam inherits from Eggs inherits from Cheese > > is not the same as > > Spam inherits from Cheese inherits from Eggs > > in the general case. > > We've all done "What the hell was I thinking?!?" errors when > programming. I'm sure I've done sillier. > And we've all made changes while saying "this shouldn't change anything", only to discover that they actually did break things. ChrisA ___ 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/3PNLSPQGYW2XO2DPXJCQGH7BEXV2JEKH/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sun, Apr 10, 2022 at 01:53:37PM -, malmiteria wrote: > David Mertz, Ph.D. writes: > > I guess the main threshold to try to cross is ONE person other than > > malmiteria in the universe of Python users. I don't believe that David's denials that people are confused by super() are even a little bit reasonable. Of course people are confused by super, especially when it comes to multiple inheritance. Its a confusing technique. https://fuhm.net/super-harmful/ The problem with super is not super, but MI, which is inherently hard to use correctly even if you don't misunderstand super(). > A coworker of mine once switched the order in which class were > inherited from stating it wasn't gonna change anything. Yes well that was just silly. Of course the order matters. Even in single inheritance, the order matters: Spam inherits from Eggs inherits from Cheese is not the same as Spam inherits from Cheese inherits from Eggs in the general case. We've all done "What the hell was I thinking?!?" errors when programming. I'm sure I've done sillier. -- Steve ___ 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/2NJSJCDN3HA7S4TGII47RN2NC3UNGJKE/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Stephen J. Turnbull writes: > It may not be flexible, but it is quite useful. In most cases it's > quite trivial to pick up the version from the second parent: > > class C(A, B): > def foo(self, *args): > return B.foo(self, *args) > # we don't define bar() because we want C to inherit A's > # version This exemple shows, a dissymmetry between foo and bar, in cases A and B share a parent P. foo method only visits C, B then P bar visits C, A, B, P You'd need to return A.bar in C bar methods to get more symmetry, but what if you wanted foo to visit the inheritance tree in this order? C, B, A, P. (While having bar visiting them in this order C, A, B, P) How would you go about it? > The questions are > > 1. Are there any "!#$%ing Python" cases that cannot be worked around? > 2. How frequent are the "!#$%ing Python" cases compared to the Just > Works cases? > 3. How painful are the workarounds? Actually, there's more questions to be asked. I would add: - Is there any problems at any steps of the programming experience (producing a feature, debugging, testing, refactoring, logging, and so on) I would argue the debugging experience in multiple scenarios i've presented are horrible today, some refactoring aren't possible (more on that later), and overall, the problem is the learning curve. - For those problems, are the solution accessible to everyone? Not everyone knows where to find docs, not everyone who finds docs knows how to read it, not everyone who knows how to read it will understand it, and so on. For the refactoring example, i believe it to be a good answer to your "Are there any "!#$%ing Python" cases that cannot be worked around?" Assume you're a lib author. You're providing a few classes, let's say about cook's styles. Each class has multiple methods, clean, slice, dice, mince, and so on. Your lib turned out quite successful, and you've been requested to add a few more cook's styles. While adding those, you realise you're repeating a lot of the clean method, but not all of it. So, you refactor it, as you now identify a few cleaning styles. You start from something like that: ``` class FrenchCook: def clean(self): print("baguette") print("fromage") print("european cleanning style") class GermanCook: def clean(self): print("beer") print("european cleanning style") ``` And end up with something like this. ``` class EuropeanCleaning: def clean(self): print("european cleanning style") class FrenchCook(EuropeanCleaning): def clean(self): print("baguette") print("fromage") super().clean() class GermanCook(EuropeanCleaning): def clean(self): print("beer") super().clean() ``` Do you see the problem with this refactoring? Keep in mind that your lib is used a lot, so any API change won't be possitively received by your lib users. Meaning composition is not an option. If you can't see the problem with this refactoring, that's my point, because there's one. If you can see the problem with this refactoring, good for you. The problem is still there. Is there a refactoring that wouldn't exhibit this problem, yes. This solution has it's own issues, that i'll talk about once you answer me. i wouldn't wanna spoil the exercice by giving you the answer. Actually, this could be one question i'll add into the form i'm getting ready. I'll give it to you all so we can agree on the fairness of the questions first, and stuff like that, before running it. > That doesn't "look like" a mixin, though. That looks like a simple > inheritance chain Our experiences with mixins seems very different, i've consistently seen them used as a way to "extend" the not mixin class behavior. The adoption syntax i propose *is* a simple inheritance chain (in this exemple), and that's the goal. Mixins in your experience seems to be a lot more 'compositional' and for them, my proposal wouldn't change much. They would still be used the same way. There would be one major difference, which is that when multiple mixins provide the same attribute / method, accessing this attrribute / method would raise an ExplicitResolutionRequired error, instead of leaving it be just like that. That would reduce the risk of missing that possible error, and make the error actually related to the source of the error. Solutions to fix this errors aren't hard to provide : either mixins need to rename their attributes / method with a double underscore at first, or the mixin user can just redefine the method / select which to use, by assigning the mixin.method to the class method. ___ 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
[Python-ideas] Re: mro and super don't feel so pythonic
David Mertz, Ph.D. writes: > Malmiteria is the FIRST person I've met "confused" by super(). No need to capitalise the first letter in malmiteria. I'm not sure what the quotes surrounding confused mean. What do you mean by those? > I guess the main threshold to try to cross is ONE person other than > malmiteria in the universe of Python users. A coworker of mine once switched the order in which class were inherited from stating it wasn't gonna change anything. That's your one occurence i guess. I know you meant it more as an insult than as a genuine "if you can find one other guy, i'll accept your proposal", but well, here it is, so, either do accept my proposal, or tell me what would be to you the reasonable threshold to meet. I'm not sure a threshold on its own is the right thing to look for, if you think there's a better metric, please let me know. ___ 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/3SG6CNP6XBEZL3XQCJGCOXBEHHEOC4Q4/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Matsuoka Takuo writes: > For your particular case of a diamond, the solution below seems > simpler to me than yours. What problems may it create which your > solution won't? Or you might refine the problem. It's not easy to > see the real value of your suggestions. > > ``` > class HighGobelin: > def scream(self): > self._speak() > print("raAaaaAar") > def _speak(self): > return > > class CorruptedGobelin(HighGobelin): > def _speak(self): > print("my corrupted soul makes me wanna scream") > > class ProudGobelin(HighGobelin): > def _speak(self): > print("I ... can't ... contain my scream!") > > class HalfBreed(ProudGobelin, CorruptedGobelin): > @property > def _speak(self): > return super( > __class__ if random.choices([True, False]) > else ProudGobelin, > self > )._speak > ``` > > Best regards, > Takuo Matsuoka There's a few problems, mainly, if you provide ProudGobelin and CorruptedGobelin as a lib author, you're very likely not to think of the HalfBreed use case, so the lib users wanting to create the HalfBreed class is bared from this solution, as it requires some work on ProudGobelin and CorruptedGobelin classes. Another one is that even if you're not in the case of a lib, you're likely not to think of this solution (depending on your skills / experiences with python), and not to identify the problem on its own, and debugging it will be a nightmare, unless you already know about super tendency to jump sideway. The problem is not that we can't come up with solutions now. Thanks for your constructive participation :) ___ 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/CXSL5YFIDR5423465WGA3DYXDY5273N3/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
For your particular case of a diamond, the solution below seems simpler to me than yours. What problems may it create which your solution won't? Or you might refine the problem. It's not easy to see the real value of your suggestions. ``` class HighGobelin: def scream(self): self._speak() print("raAaaaAar") def _speak(self): return class CorruptedGobelin(HighGobelin): def _speak(self): print("my corrupted soul makes me wanna scream") class ProudGobelin(HighGobelin): def _speak(self): print("I ... can't ... contain my scream!") class HalfBreed(ProudGobelin, CorruptedGobelin): @property def _speak(self): return super( __class__ if random.choices([True, False]) else ProudGobelin, self )._speak ``` Best regards, Takuo Matsuoka ___ 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/JNZEO3PWUG225OBOSKRMPHEYEYAXDUXC/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Sat, Apr 9, 2022, 7:31 AM malmiteria wrote: > Joao S. O. Bueno writes: > > You are still repeating this: > > "more in line with the expectation of the majority, " > > Though, as already asked, there is zero (nothing) to support that. > Here's some more evidence of a sort: I've taught hundreds, maybe thousands, of scientists and software developers Python. Some only knew different programming languages, some wanted to understand Python more deeply. Malmiteria is the FIRST person I've met "confused" by super(). Most of those are not confused because they've simply never had any reason to give it deeper thought. It never did and never will matter to them. A much smaller number were not confused because they are accustomed to using deep and branched inheritance trees, and therefore read Michele's paper on C3 MRO. Another open question is the threshold at which we would all agree there's > a problem to be fixed i guess? > I guess the main threshold to try to cross is ONE person other than malmiteria in the universe of Python users. ___ 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/HFQKMUNA6MQMYJF3KESXN227H7J34X22/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Greg ewing writes: > That sounds like exactly what Class.method(self) does today. Why > do we need another way to do it? Because that's a completely different syntax from the commonly used super, it's likely enough that some people wouldn't think of it to be a problem. Again, if you disagree with this statement, fine, argue with it, but come on now, stop ignoring my answer to your question and act like i didn't answer. > That's not the kind of knowledge I'm talking about. You need to know > a lot about how those particular classes behave -- what their methods > do, whether they would conflict with each other in any way, what the > consequences would be of calling them in various orders, etc. First of all, LOL who is even doing that? I get that you need to know a minimum about anything before using it, but diving in depths in any library you use is not the norm, to say the least. Second of all, how would you go about that? running instances of those classes, and watching their behavior? reading the docs (that would talk about their independant behavior, and never care to explain if any method calls super)? something else? You would still get the surprise when inheriting from 2 classes that sometimes, one's behavior would be overriden by the other, or that one's behavior is 'interrupted' by the other. Sometimes that's what you want, as in cases where you only want one commit to a database, for exemple. But not in all cases. And you have no way to tell before actually running the code. > You seem to think that removing the MRO and making super work the > way you imagine it should would make it easy to grab any bunch of > arbitrary classes and inherit from them and everything would be fine > and dandy. Well, it would make for an easier experience in those hard MI cases, and an equivalent experience in the simple cases. > I still don't understand how you expect a particular super call > in a particular method to somehow be able to jump sideways when > you want it to and not other times. Simple. I never want it to jump sideways. > You'll have to provide a > detailed example, not just vague waffling about mixins and > proxying. Okay, but waffles are good tho. again, read it : https://github.com/malmiteria/super-alternative-to-super/tree/master/conversation#way-too-big-combinatory-possibilities It's been up for a long time now. I'll just repeat it here, so you can't complain about having to click once (and you tell me people read the docs huh?): assume you're making a web framework, you'll have a lot of View classes, based on different needs: ``` class GenericView: def render(self): # does something generic class ModelView: def render(self): # does something related to models class DetailView: def render(self): # does something for one instance of a model class ListView: def render(self): # does something for all instance of a model ``` Now, you also wanna allow for some of those view to require users to be logged in, or have the permission to access it. You could create a PermissionGenericView, a PermissionDetailView, and so on, but that's not DRY at all, so you kinda have to do it like that: ``` class Permission: def render(self): if not self.user.has_perm(): raise PermissionError return super().render() class LoginRequired: def render(self): if not self.user.is_logged_in(): raise LoginError return super().render() ``` Then, your frameworks users would have to integrate those view and mixins like that: ``` class MyView(Permission, DetailView): pass ``` Turns out, this : ``` class MyView(DetailView, Permission): pass ``` Is not equivalent at all, since it completely mutes Permission render. In this case, what you really want is Permission to inherit from DetailView as it is meant to extend it's render behavior. My adoption proposal is to allow for this syntax: ``` class MyView(Permission(DetailView)): pass ``` Which makes it so that MyView inherits from Permission, which itself inherits from DetailView. I'd argue it's also quite intuitive as you can see here it was the first reaction of Stephen J. Turnbull to this syntax: Stephen J. Turnbull writes > malmiteria writes: > > That's why my proposal for those cases is to allow inheritance to > > be postponed after definition time, and set by the final child > > class that inherits from those. > > > > class Sphynx(Hairless(Cat)): pass > That doesn't "look like" a mixin, though. That looks like a simple > inheritance chain And that despite the fact that Stephen and I 's experiences with mixins seems very different. I've mostly been confronted with mixin that do extend their non mixin class behavior. Hence the reason of me presenting adoption as an alternative to mixins. However, if mixins are used like in Stephen's experiences, meaning, essentially gluing together a bunch of attributes / method that are meant not to
[Python-ideas] Re: mro and super don't feel so pythonic
Joao S. O. Bueno writes: > You are still repeating this: > "more in line with the expectation of the majority, " > Though, as already asked, there is zero (nothing) to support that. I'm also still repeating: People most common experience with super informs their understanding and expectations of super's behavior. This experience will inform them that super proxies "the" (in quotes because it's unclear what it targets, not because it means there's only one, in term of what it teaches users about its behavior) parent. That is not enough to understand its behavior in MI. Also, they would see super always go upward the inheritance trees, so having it going sideway *is* not in line with the expectation of the majority. This is not a "court of law" type of proof, but it's hard to refute that there is a mismacth between expectation informed by experience in simple case and behavior in MI cases. Since simple cases are by far the most common, they do inform the expectation of the majority, i don't know why you think there's nothing to support that. It's also quite "common knowledge" that super is one of the most confusing features of python. I guess that's another argument that supports this same idea. This one has more evidence attached to it, as mentionned by Steven D'Aprano : stackoverflow posts, or even the simple fact that raymond hettinger had to dedicate a talk to this feature. So since it's more evidence based, i guess it's a stronger argument. I get that you've been mostly silent here, but you or anyone else here never answered to this critic of super, except maybe with a "no" type of answer maybe. Very constructive. > I don't think things have improved, but you sure are consuming everyone's > time I wonder why things aren't moving on when no one addresses my answers... > I replied in private as that user's needs could > be fulfilled with a custom metaclass, offering personal help with that (and > did not get a reply). If you are talking about a different mail from your fist answer in this thread, it never reached me, i'm sorry (i checked my spams, but it's not there either). > So, I'd suggest to you, if not for others, at least for myself, that you'd > get some > backup on what this "majority" you claim could be. Could you set, I don't > know, > some online form? With questions like: > > "on the following scenario, what do you [think|prefer] 'super' [does|could > do]?" > > Then we can check. No need for "majority" - get at least some 10 > respondents, with 2 or 3 of those > thinking the same as you, and then maybe it would make sense insisting > on this path, as there could be something in there. Sure, before i start on this path, is anyone else here requesting that too? If there's any question you feel would add value / information to the discussion, let me know. Since the point we're not agreeing on is that people expectations are (or not) in line with super's actual behavior, i think it matter that the questions are open enough. A question that gives a lot of possible answers might hide the fact that someone would have never come up with those answer themselves, which is what their "real life experience" would have been. A question like this one: Chris Angelico writes: > In the given scenario, which of these lines of code would you expect > to have this behaviour? > * super().method() > * ParentClass.method() > * method() > * ::method() > * ^method() > * super[1].method() could come, but only after more open questions, so as not to taint the open questions answers. Eventually, we could also ask people if they have ever seen any of that list of possible answers, or used it themselves. I would add the super(Class).method() syntax in the mix, after all that's my proposal. welcome back chris btw. Another open question is the threshold at which we would all agree there's a problem to be fixed i guess? Joao S. O. Bueno proposes 2-3 over 10, so i guess 25% I'd argue that even a lower number, given the size of the python population, is still a problem. But 25% is fine by me. We could also ask them plainly what they think super should do, in some given scenarios, with multiple possible answers. That's a way to measure what behavior they expect the most, out of multiple possible behavior. Not 'which is the most common expectation' but more 'what expectation out of those specifically is the most common' type of question. Joao S. O. Bueno writes: > Otherwise, just admit these are some features you thought of yourself I did. > not even you seem > to be quite sure of which should be the specs or deterministic outcome (if > any) mathematically deterministic, or "humanly" deterministic? (meaning, majority of people would get the proper expectation, / least surprise, on top of it's behavior being mathematically deterministic). After all, randomisation is deterministic, but we still consider it random. > Get your ideas out into some > packages I've linked it so
[Python-ideas] Re: mro and super don't feel so pythonic
On Fri, 8 Apr 2022 at 22:56, Joao S. O. Bueno wrote: > > Hi. I've replied to the first e-mail on this thread, more than 10 days ago. > I am back, though I've read most of what was written. > > I don't think things have improved, but you sure are consuming everyone's time > > You are still repeating this: > "more in line with the expectation of the majority, " > > Though, as already asked, there is zero (nothing) to support that. > I've seen exactly _one_ e-mail among those in the thread, that seemed > to need something different from the current status quo - though not > exactly what you offer. I replied in private as that user's needs could > be fulfilled with a custom metaclass, offering personal help with that (and > did not get a reply). > > So, I'd suggest to you, if not for others, at least for myself, that you'd > get some > backup on what this "majority" you claim could be. Could you set, I don't > know, > some online form? With questions like: > > "on the following scenario, what do you [think|prefer] 'super' [does|could > do]?" > > Then we can check. No need for "majority" - get at least some 10 respondents, > with 2 or 3 of those > thinking the same as you, and then maybe it would make sense insisting > on this path, as there could be something in there. > While I admire the intent here, unfortunately, a survey like that is almost completely useless. It's easy to trap people into thinking that super does something different from what it does, but that still doesn't show that super needs to be changed. It might be better to word it like this: In the given scenario, which of these lines of code would you expect to have this behaviour? * super().method() * ParentClass.method() * method() * ::method() * ^method() * super[1].method() and ask people to rank them in order of which ones make the most sense. I still don't think the survey would be hugely useful, but this sort of wording is a better way of judging people's expectations than asking them to describe the behaviour of a short form like "super().method()". ChrisA ___ 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/BHEC4L2NNXERGIX4DVJS2F6ESWKPB3GQ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Hi. I've replied to the first e-mail on this thread, more than 10 days ago. I am back, though I've read most of what was written. I don't think things have improved, but you sure are consuming everyone's time You are still repeating this: "more in line with the expectation of the majority, " Though, as already asked, there is zero (nothing) to support that. I've seen exactly _one_ e-mail among those in the thread, that seemed to need something different from the current status quo - though not exactly what you offer. I replied in private as that user's needs could be fulfilled with a custom metaclass, offering personal help with that (and did not get a reply). So, I'd suggest to you, if not for others, at least for myself, that you'd get some backup on what this "majority" you claim could be. Could you set, I don't know, some online form? With questions like: "on the following scenario, what do you [think|prefer] 'super' [does|could do]?" Then we can check. No need for "majority" - get at least some 10 respondents, with 2 or 3 of those thinking the same as you, and then maybe it would make sense insisting on this path, as there could be something in there. Otherwise, just admit these are some features you thought of yourself, and not even you seem to be quite sure of which should be the specs or deterministic outcome (if any) when calling parent class methods with M.I. Get your ideas out into some packages, gists, blog posts - some of what you want can be got with custom metaclasses (except when retrieving dunder methods for operators, like __add__), and I can even help you to come up with those if you want. But these are toys nonetheless, which might see the "light of the day" maybe once a year in a codebase. best regards, js -><- On Thu, Apr 7, 2022 at 12:39 PM malmiteria wrote: > Antoine Rozo writes: > > If the only feature you need from super is the proxy one, why don't you > > code your own parent-proxy-type? > > I did : > https://github.com/malmiteria/super-alternative-to-super/blob/master/parent.py > > This is irrelevant to the discussion we're having i think. > Essentially, I'm arguing against today's state of some edge case of MRO + > super, and against the UX associated with it. > Those are issues with today's python, and the update that i propose would > reduce the UX problems with super and MRO, would allow for use case of > super more in line with the expectation of the majority, and would open the > door to a few cases locked behind MRO errors today. > Technically, with my proposal, you could even do circular inheritance, > which is definitely unheard of today: > ``` > class Day: > def tell_time(self): > print("it's daytime") > sleep(1) > super().tell_time() > > class Night(Day): > def tell_time(self): > print("it's night time") > sleep(1) > super().tell_time() > > Day.__bases__ = (Night, ) > > Day().tell_time() # infinitely loops over "it's daytime" and "it's night > time" > ``` > That would be an incredibely easy way to articulate process that repeat in > a cycle, with no end, cron style. > No need to get multiple class too: > ``` > class CronTask: > def task(self): > # do something > time.sleep(1) > super().task() > > CronTask.__bases__ = (CronTask, ) > > CronTask().task() # runs the task forever with a time sleep in between > ``` > > I'm convinced there's some smart designs that are banned from python > because of MRO and super's limitations. > ___ > 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/BKFSLLICTCAYBPIZBTVW4Y4OPT3UKBZ2/ > Code of Conduct: http://python.org/psf/codeofconduct/ > ___ 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/BVZ7UIEHFGX3V66P2COWOY7UK3WCCSDA/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Thu, Apr 07, 2022 at 11:52:31AM -, malmiteria wrote: > I believe my gobelin exemple is a fair case of MI since we can > definitely say halfbreed *is a* corruptedgobelin *and a* proudgobelin. That is the most common relationship modelled by inheritance. > In such a case with multiple *is a* there's multiple strategies to > blend in the multiple *is a*. And super does that correctly. Except that you prefer to use a different design that is not well- modelled by inheritance, but is well-modelled by delegation. And then for some reason, you insist on using super. > Another strat is to say that some attributes / behaviors of one parent > override the over, like dominant genes. Don't be fooled by the name, inheritance in programming languages does not model DNA. It is a simple model useful for programming. > Today's MRO implicitely overrides all method from the second parent > with method from the first parent. Right, because it models **cooperative inheritance**, not DNA. A method in one class overrides that in classes later in the MRO unless it cooperatively passes the call on to the next class in the MRO. > Essentially, the first parent (in declaration order) is dominant on > all attributes. This isn't very subtle, as we could want some > attribute of each parent to be dominant, while others to be recessive. This is all very hypothetical. You could want Intercal's COMEFROM statement too, but why would you? MI is complicated enough without intentionally trying to make it arbitrarily more complicated, when instead you can just use composition or delegation instead. You want to write this: super(ProudGobelin, self).method() But you can already do that, using less typing, and get exactly the same effect: ProudGobelin.method(self) That does everything you want, and saves you seven characters. Less typing, more efficient, works today in standard Python, no special imports needed or changes to the interpreter or language. All you need to do is **don't use super** for things that don't need super. The only reason you won't use it is that you insist on using the screwdriver of super() to hammer in the nails of delegation. -- Steve ___ 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/MQALSNQXYYKBKOLAZV6EIG2WCNXSAWAK/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 7/04/22 11:11 pm, malmiteria wrote: But if there was a way to tell super what class it should be a proxy of, that would be very easy to explain : when there's two parent, just give the parent you want to target as an argument to super. That sounds like exactly what Class.method(self) does today. Why do we need another way to do it? It requires knowing a *lot* about the classes you're inheriting from, *today*, and that's a problem I'm trying to adress. And you being able to tell those 2 classes have some sort of common ancestry wouldn't be of much help if you don't already know about MRO and the effect it might have on inherited classes in case of multiple inheritance. That's not the kind of knowledge I'm talking about. You need to know a lot about how those particular classes behave -- what their methods do, whether they would conflict with each other in any way, what the consequences would be of calling them in various orders, etc. You seem to think that removing the MRO and making super work the way you imagine it should would make it easy to grab any bunch of arbitrary classes and inherit from them and everything would be fine and dandy. It would not! The Mixin use case, where we explicitely use the super ability to side jump so that our mixin 'specialise' the last class in MI order would really benefit from a feature allowing a class to select a parent after being defined. I still don't understand how you expect a particular super call in a particular method to somehow be able to jump sideways when you want it to and not other times. You'll have to provide a detailed example, not just vague waffling about mixins and proxying. -- Greg ___ 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/SFAQ3APFZXNFJQCHMO2Q7OAEMZ5D6I7Z/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 7/04/22 11:52 pm, malmiteria wrote: I believe my gobelin exemple is a fair case of MI since we can definitely say halfbreed *is a* corruptedgobelin *and a* proudgobelin. I'm not so sure about that. I would agree that it's a gobelin, just as you are (presumably) a human. But a child is *not* its parents -- it's a human in its own right that happens to have some characteristics of one parent and some of the other. I'm not sure MI is such a good way to model that kind of relationship. -- Greg ___ 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/KCV4Y3XNW5IVDMOCGWSNOZZ2DTZBDA5P/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
If these examples were possible (I wouldn't say they are smart designs) they would lead to recursion errors. Limitations on MRO are good, they force to keep a quite simple structure. Le jeu. 7 avr. 2022 à 17:41, malmiteria a écrit : > Antoine Rozo writes: > > If the only feature you need from super is the proxy one, why don't you > > code your own parent-proxy-type? > > I did : > https://github.com/malmiteria/super-alternative-to-super/blob/master/parent.py > > This is irrelevant to the discussion we're having i think. > Essentially, I'm arguing against today's state of some edge case of MRO + > super, and against the UX associated with it. > Those are issues with today's python, and the update that i propose would > reduce the UX problems with super and MRO, would allow for use case of > super more in line with the expectation of the majority, and would open the > door to a few cases locked behind MRO errors today. > Technically, with my proposal, you could even do circular inheritance, > which is definitely unheard of today: > ``` > class Day: > def tell_time(self): > print("it's daytime") > sleep(1) > super().tell_time() > > class Night(Day): > def tell_time(self): > print("it's night time") > sleep(1) > super().tell_time() > > Day.__bases__ = (Night, ) > > Day().tell_time() # infinitely loops over "it's daytime" and "it's night > time" > ``` > That would be an incredibely easy way to articulate process that repeat in > a cycle, with no end, cron style. > No need to get multiple class too: > ``` > class CronTask: > def task(self): > # do something > time.sleep(1) > super().task() > > CronTask.__bases__ = (CronTask, ) > > CronTask().task() # runs the task forever with a time sleep in between > ``` > > I'm convinced there's some smart designs that are banned from python > because of MRO and super's limitations. > ___ > 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/BKFSLLICTCAYBPIZBTVW4Y4OPT3UKBZ2/ > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Antoine Rozo ___ 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/NFHV3F2ELGZ6EW6QHDNOQGLZHNHJ54HH/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
malmiteria writes: > to dive into conceptual ideas a bit more: I'm not sure why you assume that nobody knows this stuff, at least at the extremely high and fuzzy level of your discussion. Executive summary: I see a lot of theory in your posts, but it's very difficult to tie it to *my* practice, and you don't go into any detail about *your* practice that requires the features you propose. > inheritance is usually what we do when we mean *is a* This really isn't very useful. Much more useful would be Class Cat should inherit from class Animal if all concrete attributes of Animal are appropriate for Cat, and all abstract attributes of Animal can be instantiated appropriately for Cat. *** This is what we mean when we say a cat *is an* animal. *** The more you reduce "all" to "most", the less appropriate inheritance is. > In such a case with multiple *is a* there's multiple strategies to > blend in the multiple *is a*. This is true. Given the rarity of multiple inheritance, and especially the rarity of cases where the C3 MRO "gets it wrong", you need to do a lot more than just point out the multiplicity. You have to demonstrate a need to support other cases. IMO, it's *not* important to support the cases where all of the parent methods of the same name should be called by automatically calling all of them. In Python, it's very easy to implement this directly if necessary. On the other hand, if we default to calling all parent methods of the same name, it's very difficult to work around that, even impossible if you can't modify the parent classes. And this is subject to one the same complaint that you make about the MRO, as for some methods you might want all parent methods called, and others you want only one (or a larger proper subset). > Today's MRO implicitely overrides all method from the second parent > with method from the first parent. > Essentially, the first parent (in declaration order) is dominant on > all attributes. > This isn't very subtle, as we could want some attribute of each > parent to be dominant, while others to be recessive. It may not be flexible, but it is quite useful. In most cases it's quite trivial to pick up the version from the second parent: class C(A, B): def foo(self, *args): return B.foo(self, *args) # we don't define bar() because we want C to inherit A's # version But in my experience it's rarely needed. Mostly, there's a primary parent class that provides most of the functionality, and there are skeletal mixins which have one job each. YMMV. > My "can't assume one parent is more specialised" As I've pointed out before, Python makes no such assumption. Python *forces* you to specify the order of parent classes, and defines the semantics so that each parent takes precedence over any that follow it in the class declaration. Python assumes that will Just Work for you. If it doesn't, you have to curse Python and work around it. Python shrugs your curse right off, though. The questions are 1. Are there any "!#$%ing Python" cases that cannot be worked around? 2. How frequent are the "!#$%ing Python" cases compared to the Just Works cases? 3. How painful are the workarounds? AFAICS, you have consistently doubled down on the nonsense quoted above, and have not even tried to answer any of questions 1-3 with concrete examples of code somebody actually uses. The exception is your story about your colleague's issue with order of parents in one class in one Django application. The answers in that story as you told it are 1. Not here. 2. This was not a "!#$%ing Python" case. 3. No workarounds needed, just don't fix what ain't broke. > That's why my proposal for those cases is to allow inheritance to > be postponed after definition time, and set by the final child > class that inherits from those. > > ``` > class Sphynx(Hairless(Cat)): pass > ``` That doesn't "look like" a mixin, though. That looks like a simple inheritance chain, and if so the "(Cat)" is redundant and Hairless is very badly named because it doesn't tell you it's a cat. Sure, you can tell me Hairless is a mixin applied to Cat, and Hairless does not inherit from Cat, but I'm still going to WTF every time I see it. Not sure what this "postponed inheritance" is supposed to mean, but that's not a good way to write it, I'm pretty sure. Also, Sphynx is a pretty horrible example. Given the diversity of the animal kingdom, Animal is almost certainly a (very) abstract base class, with almost all characteristics added by composition. Even within the Felidae, there is an awful lot of variation. So I would expect Hairless to not even exist, and for Sphynx to look like: class Sphynx(Cat): def __init__(self, *args): super().__init__(*args) self.hair = None You could make Hairless a mixin class: class Hairless: def __init__(self, hair=None):
[Python-ideas] Re: mro and super don't feel so pythonic
Antoine Rozo writes: > If the only feature you need from super is the proxy one, why don't you > code your own parent-proxy-type? I did : https://github.com/malmiteria/super-alternative-to-super/blob/master/parent.py This is irrelevant to the discussion we're having i think. Essentially, I'm arguing against today's state of some edge case of MRO + super, and against the UX associated with it. Those are issues with today's python, and the update that i propose would reduce the UX problems with super and MRO, would allow for use case of super more in line with the expectation of the majority, and would open the door to a few cases locked behind MRO errors today. Technically, with my proposal, you could even do circular inheritance, which is definitely unheard of today: ``` class Day: def tell_time(self): print("it's daytime") sleep(1) super().tell_time() class Night(Day): def tell_time(self): print("it's night time") sleep(1) super().tell_time() Day.__bases__ = (Night, ) Day().tell_time() # infinitely loops over "it's daytime" and "it's night time" ``` That would be an incredibely easy way to articulate process that repeat in a cycle, with no end, cron style. No need to get multiple class too: ``` class CronTask: def task(self): # do something time.sleep(1) super().task() CronTask.__bases__ = (CronTask, ) CronTask().task() # runs the task forever with a time sleep in between ``` I'm convinced there's some smart designs that are banned from python because of MRO and super's limitations. ___ 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/BKFSLLICTCAYBPIZBTVW4Y4OPT3UKBZ2/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
malmiteria writes: > Stephen J. Turnbull writes: > > One really plausible example is given in Raymond's piece: a later > > version of the same library refactors a "monolithic" class as a child > > of one or more "private" classes that are not intended to be exposed > > in the public API, but your multiply-derived class *written before the > > refactoring* Just Works. As far as I can see, super(), and maybe even > > the deterministic MRO, is needed to make that work. > I'm curious about this exemple, do you have a link to share so i > could have a look at the code / change in code? This could be a > good exercice. The example is not code, it's a description of a case where you would definitely not know the class hierarchy at execution time because it changes after you release your code. It's described in "Python's super() considered super!" But you don't need to read it, there are no more details than what's quoted above. ___ 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/7QBPZL4BOKYKODXW2NQYCHZC5BJUGSQR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
to dive into conceptual ideas a bit more: inheritance is usually what we do when we mean *is a* for exemple, a cat *is an* animal, so we would write it like that: ``` class Animal: pass class Cat(Animal): pass ``` I believe my gobelin exemple is a fair case of MI since we can definitely say halfbreed *is a* corruptedgobelin *and a* proudgobelin. In such a case with multiple *is a* there's multiple strategies to blend in the multiple *is a*. One strat is chaining the *is a* : a cat *is an* animal, and an animal *is a* living being. We simply chain simple inheritance. Another strat is to say that some attributes / behaviors of one parent override the over, like dominant genes. Today's MRO implicitely overrides all method from the second parent with method from the first parent. Essentially, the first parent (in declaration order) is dominant on all attributes. This isn't very subtle, as we could want some attribute of each parent to be dominant, while others to be recessive. My "can't assume one parent is more specialised" (can be found here : https://github.com/malmiteria/super-alternative-to-super/blob/master/conversation/README.md#cant-assume-on-parents-more-specialised) showcases such a scenario. The diamond problem essentially raises the question, if you are a 1 and a 2, and 1 and 2 are numbers, are you a number twice, or once? If by 1 and 2 you mean 3, you're a number once. If by 1 and 2 you mean (1, 2) you're a number twice. Today, it defaults to once in all cases. This can cause unexpected behaviors, such as showcased by the gobelin exemple (can be found here : https://github.com/malmiteria/super-alternative-to-super/blob/master/conversation/README.md#diamond-tree-repeat-top) I believe the mixin case to be a little bit different. I think a mixin is a *but with* kind of relationship. for exemple: a sphynx is a cat, *but without* hair you can find my exemple here : https://github.com/malmiteria/super-alternative-to-super/blob/master/conversation/README.md#way-too-big-combinatory-possibilities i think it is fair to say that those scenarios are well served by simple inheritance, but can't in practice define the "but with" class as the child of any other, since the "but with" (aka mixins) could be applied to multiple parent class. That's why my proposal for those cases is to allow inheritance to be postponed after definition time, and set by the final child class that inherits from those. ``` class Sphynx(Hairless(Cat)): pass ``` Instead of ``` class Sphynx(Hairless, Cat): pass ``` Now, there's another thing in the language that today seems like a "but with" to me, and it's decorators. ``` @http_errors_handling def answer_api_calls(request): pass ``` means answer api calls, but with http errors handling. So i guess using the @ syntax could be meaningful too: ``` class Sphynx(Cat @ Hairless): pass ``` where Cat @ Hairless would produce a resulting class being a copy of Hairless, with Cat as a parent. This makes it easy to chain lots of mixins without having to add tons of parenthesis, so it might be a better syntax that the one i originally proposed. Also, some of you mentionned composition is an option for some exemples i gave. I believe composition to be more a *has a* kind of relationship. This is something i believe to be "common intuition", that's how most people are taught what OOP is. Wether it is or not, it matters to make sure that the different concepts we use always mean the same thing in all their use cases. This makes for a very smooth learning curve, compared to concepts that mutate over context. And overall, having to switch from a *is a* relationship to a *has a* relationship, simply because the langage doesn't allow *is a* in some cases hints at excessive limitations of the langage. ___ 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/FFOQHTR47WF7GQYDWBU6SKEBW57IVLZS/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
If the only feature you need from super is the proxy one, why don't you code your own parent-proxy-type? class parentproxy: def __init__(self, cls, obj): self.__thisclass__ = cls self.__self_class__ = type(obj) self.__self__ = obj def __getattr__(self, name): attr = getattr(self.__thisclass__, name) if hasattr(attr, '__get__'): attr = attr.__get__(self.__self_class__, self.__self__) return attr class A: x = 0 y = 1 def method(self): return 'A.method' class B(A): y = 2 def method(self): return 'B.method' obj = B() # prints 0, 0, 0 print(obj.x, parentproxy(B, obj).x, parentproxy(A, obj).x) # prints 2, 2, 1 print(obj.y, parentproxy(B, obj).y, parentproxy(A, obj).y) # prints B.method, B.method, A.method print(obj.method(), parentproxy(B, obj).method(), parentproxy(A, obj).method()) It gives the proxy you need and it works well with multiple inheritance too. Le jeu. 7 avr. 2022 à 13:14, malmiteria a écrit : > Greg Ewing writes: > > If I were teaching a newcomer about super, I wouldn't even tell them > > that it *has* a class argument. So they wouldn't have any expectation > > about targeting, because they wouldn't know about it. > > I would probably teach newcomers the argumentless form only too. That's > all they'll need. But argument or not, they need to know "what" does super > proxy, and the simple answer, for a newcomer, is "the parent". > If they were to ask me what happens when there's multiple parents, i would > definitely have to tell them not to go there, today at least, since today's > multiple inheritance is complex. > But if there was a way to tell super what class it should be a proxy of, > that would be very easy to explain : when there's two parent, just give the > parent you want to target as an argument to super. > > > It's a delicate > > operation that requires knowing a *lot* about the classes you're > > blending together. > > In this case, the fact that both class names have the form > > Gobelin would make me suspect quite strongly that they > > *do* have some common ancestry. > > It requires knowing a *lot* about the classes you're inheriting from, > *today*, and that's a problem I'm trying to adress. > And you being able to tell those 2 classes have some sort of common > ancestry wouldn't be of much help if you don't already know about MRO and > the effect it might have on inherited classes in case of multiple > inheritance. > So you would already need to be quite knowledgable about MRO and multiple > inheritance to got the result you expect here. > > If super were to only target the parents, either the only parent for the > argumentless form, or the specified parent in case of MI, this scpeific > scenario wouldn't require you to have any extra knowledge on MRO / super / > MI. > It would already behave exactly like you would expect. > > Of course there are use cases for super following MRO. Those need to be > covered too, and not get rid of. > I think the ability of super to handle remaps after MRO injections should > be conserved, so the scenarios in which we would pass directly the class we > wanna target should allow for remapping of the parents. > Not that there's a common use for it, but still. > > The Mixin use case, where we explicitely use the super ability to side > jump so that our mixin 'specialise' the last class in MI order would really > benefit from a feature allowing a class to select a parent after being > defined. > This is the meaning of my adpotion proposal, and i believe this use case > to be the most common use case of MI in python. > We could actually consider it a case of simple inheritance that didn't say > its name. > The adoption proposal would convert those MI cases back to SI cases. > > The diamond problem on its own requires specific attention, as the gobelin > exemple i give showcases a case where we would most definitely want the top > class to be called every time it appears in the inheritance tree, but there > are other cases where we most definitely want the top class to be called > only once, case such as ORMs doing commits to databases. > My proposal is to implement a way to allow the programmer to decide what > strategy fits their needs. > the 'use_parent_mro' keyword of super would work nice in today's context, > perhaps not so nice assuming all other changes i advocate for passed first. > A class decorator / attribute deciding the strategy super should use is an > option too. Follow MRO / follow inheritance tree for exemple would be 2 > simple options. > honestly, idk what design would be the best for this case, all i know is > that the solution should allow for multiple strategies. > > > Chris Angelico writes: > > I'm curious when you would ever be subclassing something from another > > library without knowing its hierarchy. > This is common in Django. > > > Stephen J. Turnbull writes: > > One really plausible example
[Python-ideas] Re: mro and super don't feel so pythonic
Greg Ewing writes: > If I were teaching a newcomer about super, I wouldn't even tell them > that it *has* a class argument. So they wouldn't have any expectation > about targeting, because they wouldn't know about it. I would probably teach newcomers the argumentless form only too. That's all they'll need. But argument or not, they need to know "what" does super proxy, and the simple answer, for a newcomer, is "the parent". If they were to ask me what happens when there's multiple parents, i would definitely have to tell them not to go there, today at least, since today's multiple inheritance is complex. But if there was a way to tell super what class it should be a proxy of, that would be very easy to explain : when there's two parent, just give the parent you want to target as an argument to super. > It's a delicate > operation that requires knowing a *lot* about the classes you're > blending together. > In this case, the fact that both class names have the form > Gobelin would make me suspect quite strongly that they > *do* have some common ancestry. It requires knowing a *lot* about the classes you're inheriting from, *today*, and that's a problem I'm trying to adress. And you being able to tell those 2 classes have some sort of common ancestry wouldn't be of much help if you don't already know about MRO and the effect it might have on inherited classes in case of multiple inheritance. So you would already need to be quite knowledgable about MRO and multiple inheritance to got the result you expect here. If super were to only target the parents, either the only parent for the argumentless form, or the specified parent in case of MI, this scpeific scenario wouldn't require you to have any extra knowledge on MRO / super / MI. It would already behave exactly like you would expect. Of course there are use cases for super following MRO. Those need to be covered too, and not get rid of. I think the ability of super to handle remaps after MRO injections should be conserved, so the scenarios in which we would pass directly the class we wanna target should allow for remapping of the parents. Not that there's a common use for it, but still. The Mixin use case, where we explicitely use the super ability to side jump so that our mixin 'specialise' the last class in MI order would really benefit from a feature allowing a class to select a parent after being defined. This is the meaning of my adpotion proposal, and i believe this use case to be the most common use case of MI in python. We could actually consider it a case of simple inheritance that didn't say its name. The adoption proposal would convert those MI cases back to SI cases. The diamond problem on its own requires specific attention, as the gobelin exemple i give showcases a case where we would most definitely want the top class to be called every time it appears in the inheritance tree, but there are other cases where we most definitely want the top class to be called only once, case such as ORMs doing commits to databases. My proposal is to implement a way to allow the programmer to decide what strategy fits their needs. the 'use_parent_mro' keyword of super would work nice in today's context, perhaps not so nice assuming all other changes i advocate for passed first. A class decorator / attribute deciding the strategy super should use is an option too. Follow MRO / follow inheritance tree for exemple would be 2 simple options. honestly, idk what design would be the best for this case, all i know is that the solution should allow for multiple strategies. Chris Angelico writes: > I'm curious when you would ever be subclassing something from another > library without knowing its hierarchy. This is common in Django. Stephen J. Turnbull writes: > One really plausible example is given in Raymond's piece: a later > version of the same library refactors a "monolithic" class as a child > of one or more "private" classes that are not intended to be exposed > in the public API, but your multiply-derived class *written before the > refactoring* Just Works. As far as I can see, super(), and maybe even > the deterministic MRO, is needed to make that work. I'm curious about this exemple, do you have a link to share so i could have a look at the code / change in code? This could be a good exercice. ___ 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/LRKJNN7RQUEYURNZZTSRDDXBEJQO5AMA/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Chris Angelico writes: > I'm curious when you would ever be subclassing something from another > library without knowing its hierarchy. When the class is a public API, no? I'm not sure why this isn't obvious, am I missing something? One really plausible example is given in Raymond's piece: a later version of the same library refactors a "monolithic" class as a child of one or more "private" classes that are not intended to be exposed in the public API, but your multiply-derived class *written before the refactoring* Just Works. As far as I can see, super(), and maybe even the deterministic MRO, is needed to make that work. Steve ___ 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/N3PPY54NYP3S6JBL4WLBU2WHE3K4PFVW/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Thu, 7 Apr 2022 at 15:41, Greg Ewing wrote: > > if proudgobelin and corruptegobelin are published by a game_engine library, > > the game_engine user would most likely not be aware (nor should he care) > > that they both inherit from a same parent. > > If someone is going to munge those classes together using MI, they'd > better learn everything they possibly can about them. It's a delicate > operation that requires knowing a *lot* about the classes you're > blending together. > > In this case, the fact that both class names have the form > Gobelin would make me suspect quite strongly that they > *do* have some common ancestry. > I'm curious when you would ever be subclassing something from another library without knowing its hierarchy. For instance, it's quite common to subclass a GTK object to create your own functionality (subclass Window to create MyApplicationWindow, subclass HButtonBox to create BoxOfMyButtons, etc), but the docs are very clear about what each class's hierarchy is - it's a vital part of the API. The idea that someone would MI two classes from the same library and not know that they inherit from the same thing is a little odd IMO. ChrisA ___ 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/X4IJ4LBI4SGYSUACIG7YFOQI4GF37IWW/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 7/04/22 5:22 am, malmiteria wrote: Also, i believe the idea of using anything but super to access a parent methods is far from obvious to most people. That might be true for people who learned Python recently enough. When I started using Python, super didn't even exist, so I got used to thinking of Class.method as the *normal* way to call inherited methods. When super first appeared I saw it as something you only use when you particularly need it, i.e. when doing cooperative MI. This alone justifies the idea that any newcomer to this kind of problem would try to use super, at least at first. And possibly wouldn't expect super targeting to behave like it does. If I were teaching a newcomer about super, I wouldn't even tell them that it *has* a class argument. So they wouldn't have any expectation about targeting, because they wouldn't know about it. if proudgobelin and corruptegobelin are published by a game_engine library, the game_engine user would most likely not be aware (nor should he care) that they both inherit from a same parent. If someone is going to munge those classes together using MI, they'd better learn everything they possibly can about them. It's a delicate operation that requires knowing a *lot* about the classes you're blending together. In this case, the fact that both class names have the form Gobelin would make me suspect quite strongly that they *do* have some common ancestry. -- Greg ___ 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/MOIQ3XPXI5O5HX4VRFFOBHIILNA35GQT/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > > All we have today is the screwhammer, and in cases the screw part > > don't work, you're telling me to get rid of it all. hammer part > > included. > That's not how I see it. > I see that we have a screwdriver (inheritence, including multiple > inheritence) which is designed for the cases where you, the programmer, > don't want to manually specify which superclass method to call, you want > the interpreter to do it using the defined linearisation. > And then we have a hammer, composition/delegation, for when you *do* > want to control what method is called. What i meant was that today's super does 2 things : it decide its target, and then, it proxyies to it. In my gobelin exemple, we would still benefit from a proxy feature, but since the targeting algorithm of super can't match our needs, we need to let go of it. And while doing so, we have to let go of super proxying feature. Also, i believe the idea of using anything but super to access a parent methods is far from obvious to most people. Imagine you've spent your entire python life doing that with super. You're likely not to think of the class.method syntax, especially since it's almost never used in any other scenarios. at least in my 5-6 years of python (with and without multiple inheritance, may i add), I never encountered such a scenario. This alone justifies the idea that any newcomer to this kind of problem would try to use super, at least at first. And possibly wouldn't expect super targeting to behave like it does. After all, inheritance means "child *is a* parent". In the gobelin case, halfbreed *is a* proudgobelin, as much as it *is a* corruptedgobelin. So what we, (experienced people that might already have learnt from painful experiences) would consider a naive implementation, makes sense, in term of concepts relationships. On top of that, if proudgobelin and corruptegobelin are published by a game_engine library, the game_engine user would most likely not be aware (nor should he care) that they both inherit from a same parent. You would most definitely not expect proudgobelin behavior to 'extend' corruptedgobelin behavior, as in this scenario, they are completely independant, as far as you know. And let's face it, we would never make sure 2 classes we import from a library aren't sharing a parent. This could happen to all of us. The most likely way for us to discover that, is to burn ourselves first with this (at the time of discovering it) unexpected behavior. We could add a few keywords to super, such as target, to get the class targeted by super, use_target_mro, to get some more control over how super will visit the parent classes, and possibly instance, to pass the "self", which today has to be the second argument, and with the keyword target, we wouldn't pass the class as first argument, so that wouldn't be possibly placed in second. That would cover the gobelin case, by essentially separating the targeting algorithm from the proxy feature. But that on its own would not prevent the game_engine case. You would still have to get burnt first to realise the 2 class your inheriting from are related. Which to me is a real issue, to say the least. There are scenarios where we don't have enough knowledge to fully predict the behavior of the code we are writing, that should most definitely not happen. Steven D'Aprano writes: > I for one frequently find myself being surprised by super and the MRO, > which I interpret as *my misunderstanding* rather than a problem with > super and the MRO. As soon as you leave the nice, cosy world of single > inheritence, things get complicated. You can interpret it however you want, but i for one would never interpret a misuse of a feature as being a user's problem. And the two side of that coin are : 1 feeling that "you failed" when you couldn't use properly whatever you're trying to use (be it a python feature, or your bank website, your door knobs, or whatever) 2 Accusing users of your product to be the one in the wrong, and refusing even the idea that you, as the feature designer, could do anything about it. Which is was a lot of people on this thread are doing, simply asserting that "this is not how to use super". In fact, current misuse of a feature could be considered a 'UX smell' as much as code with too much repeatition is considered a 'code smell' Since we are discussing the design / UX of super and MRO this is actually a relevant distinction. And as much as so many of you are asserting users to be in the wrong, i disagree. Specifically in this case because the most common use case (simple inheritance) hints at a behavior of super, that turns out to be somewhat deceptive in more complex cases. This *is* the UX smell i wanna adress. And 'nah, i don't care about dumb users' is not a valid answer, as far as i'm concerned. At least in this case. Again, since super hints at a behavior it doesn't provide. I'll
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, Apr 06, 2022 at 08:28:59PM +1200, Greg Ewing wrote: > I actually think super() is misnamed and should really be called > next_class() or something like that. There might be less confusion > about its intended use then. Heh, we should rename it frábær(), that will ensure that nobody will use it without reading the documentation! :-) -- Steve ___ 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/ICKKZNHOMIDDAZU57SIGAAHRJOWHSVBQ/ Code of Conduct: http://python.org/psf/codeofconduct/