[Python-ideas] Re: mro and super don't feel so pythonic

2022-04-25 Thread Stephen J. Turnbull
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

2022-04-24 Thread Stephen J. Turnbull
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

2022-04-23 Thread malmiteria
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

2022-04-23 Thread Steven D'Aprano
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

2022-04-23 Thread Stephen J. Turnbull
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

2022-04-22 Thread Matsuoka Takuo
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

2022-04-22 Thread Steven D'Aprano
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

2022-04-22 Thread Steven D'Aprano
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

2022-04-22 Thread Matsuoka Takuo
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

2022-04-21 Thread Christopher Barker
>
> 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

2022-04-21 Thread Matsuoka Takuo
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

2022-04-20 Thread malmiteria
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

2022-04-18 Thread Stephen J. Turnbull
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

2022-04-18 Thread Greg Ewing

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

2022-04-18 Thread malmiteria
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

2022-04-17 Thread Stephen J. Turnbull
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

2022-04-17 Thread malmiteria
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

2022-04-17 Thread Greg Ewing

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

2022-04-17 Thread Greg Ewing

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

2022-04-16 Thread Steven D'Aprano
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

2022-04-16 Thread Steven D'Aprano
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

2022-04-15 Thread Greg Ewing

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

2022-04-15 Thread Greg Ewing

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

2022-04-15 Thread Steven D'Aprano
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

2022-04-15 Thread Chris Angelico
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

2022-04-15 Thread Chris Angelico
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

2022-04-15 Thread Steven D'Aprano
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

2022-04-15 Thread Joao S. O. Bueno
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

2022-04-15 Thread malmiteria
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

2022-04-15 Thread malmiteria
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

2022-04-15 Thread Chris Angelico
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

2022-04-15 Thread Steven D'Aprano
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

2022-04-15 Thread Greg Ewing

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

2022-04-14 Thread malmiteria
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

2022-04-13 Thread Chris Angelico
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

2022-04-13 Thread Greg Ewing

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

2022-04-13 Thread Eric V. Smith

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

2022-04-13 Thread Chris Angelico
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

2022-04-13 Thread malmiteria
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

2022-04-13 Thread Antoine Rozo
> 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

2022-04-12 Thread Matsuoka Takuo
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

2022-04-12 Thread Matsuoka Takuo
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

2022-04-12 Thread Eric V. Smith

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

2022-04-12 Thread David Mertz, Ph.D.
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

2022-04-12 Thread Brendan Barnwell

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

2022-04-12 Thread Steven D'Aprano
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

2022-04-12 Thread malmiteria
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

2022-04-12 Thread Joao S. O. Bueno
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

2022-04-12 Thread Chris Angelico
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

2022-04-12 Thread malmiteria
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

2022-04-12 Thread malmiteria
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

2022-04-12 Thread Matsuoka Takuo
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

2022-04-12 Thread Eric V. Smith

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

2022-04-12 Thread Ronald Oussoren via Python-ideas


> 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

2022-04-12 Thread Matsuoka Takuo
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

2022-04-12 Thread malmiteria
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

2022-04-12 Thread malmiteria
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

2022-04-12 Thread malmiteria
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

2022-04-12 Thread malmiteria
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

2022-04-11 Thread Joao S. O. Bueno
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

2022-04-11 Thread Steven D'Aprano
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

2022-04-11 Thread Chris Angelico
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

2022-04-10 Thread Stephen J. Turnbull
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

2022-04-10 Thread Steven D'Aprano
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

2022-04-10 Thread Steven D'Aprano
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

2022-04-10 Thread Steven D'Aprano
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

2022-04-10 Thread Brendan Barnwell

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

2022-04-10 Thread Chris Angelico
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

2022-04-10 Thread malmiteria
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

2022-04-10 Thread David Mertz, Ph.D.
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

2022-04-10 Thread malmiteria
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

2022-04-10 Thread David Mertz, Ph.D.
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

2022-04-10 Thread malmiteria
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

2022-04-10 Thread David Mertz, Ph.D.
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

2022-04-10 Thread Chris Angelico
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

2022-04-10 Thread Steven D'Aprano
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

2022-04-10 Thread malmiteria
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

2022-04-10 Thread malmiteria
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

2022-04-10 Thread malmiteria
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

2022-04-10 Thread Matsuoka Takuo
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

2022-04-09 Thread David Mertz, Ph.D.
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

2022-04-09 Thread malmiteria
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

2022-04-09 Thread malmiteria
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

2022-04-08 Thread Chris Angelico
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

2022-04-08 Thread Joao S. O. Bueno
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

2022-04-08 Thread Steven D'Aprano
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

2022-04-08 Thread Greg Ewing

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

2022-04-08 Thread Greg Ewing

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

2022-04-08 Thread Antoine Rozo
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

2022-04-07 Thread Stephen J. Turnbull
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

2022-04-07 Thread malmiteria
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

2022-04-07 Thread Stephen J. Turnbull
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

2022-04-07 Thread malmiteria
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

2022-04-07 Thread Antoine Rozo
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

2022-04-07 Thread malmiteria
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

2022-04-07 Thread Stephen J. Turnbull
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

2022-04-06 Thread Chris Angelico
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

2022-04-06 Thread Greg Ewing

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

2022-04-06 Thread malmiteria
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

2022-04-06 Thread Steven D'Aprano
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/


  1   2   >