[Python-ideas] Re: Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]

2022-04-15 Thread Chris Angelico
On Sat, 16 Apr 2022 at 14:25, Steven D'Aprano  wrote:
>
> On Sat, Apr 16, 2022 at 11:07:00AM +1000, 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.
>
> Which conditions would you drop? There's not that many, really. Five.
> Six if you include the "no cycles" requirement for the DAG, which I
> think is so obviously necessary that it is barely worth mentioning.

This is *exactly* the "no true Scotsman" fallacy: you have already
excluded from consideration anything that drops a condition you didn't
already drop. On the assumption that your five conditions are
essential, there's no way that you can drop any of the five conditions
and still have it count, therefore the five conditions are essential.
Your logic is circular.

It is highly arrogant to assume that nobody will ever find a way to
implement MI while dropping one of your conditions. They're not
fundamental to the definition, they're fundamental to *the way Python
does things*.

> The most subjective is the requirement for automatic conflict
> resolution. It is a legitimate design choice to give up automatic
> conflict resolution (that's what C++ and Eiffel do) but that would be a
> breaking change for Python.

Yes. A breaking change FOR PYTHON.

> So come on Chris, back up your disagreement with something objective,
> not just wishy-washy "anything might happen in the future!" nonsense.

Yet you're willing to argue that other languages don't do "full MI"
because they do things that would be a breaking change for Python?

> No, not everything is possible. We're never going to discover a new odd
> number between 3 and 5, or that 7 isn't really prime, or that cats are
> actually a type of plant, or that Australia doesn't exist.

You would be very surprised what people HAVE discovered. For instance,
it's very common to define the distance between two numbers by
subtracting one from the other, but that isn't the only
internally-consistent definition of distance that could be used.

The only things that we can completely rule out are those which are
true by definition, or can be proven mathematically or logically. A
new odd number between 3 and 5 is provably impossible. 7 is truly
prime, by the definition of primes, and any extension to that
definition (eg complex primes or Gaussian integers) must maintain
that.

Discovering that Australia doesn't exist would be world news, but
might indicate that we'd finally angered some nuclear country enough
to get ourselves completely blown off the map. (Yeah, I know countries
like Russia and the US don't have enough nukes to do that, but we have
no idea what sort of arsenal Ghandi is hiding, just waiting for his
stats to become negative...)

> So be concrete: which of my preconditions do you want to challenge?
>
> - The inheritance model automatically resolves conflicts.
>
> As I said, it is a legitimate design choice to give that up, but it
> would be a breaking change for Python so we can rule it out.
>
> In any case, languages without automatic conflict resolution do less
> than languages with them. (That might be a good thing.)

This is the essence of the "no true Scotsman" fallacy: you assume that
it's not true MI without automatic conflict resolution.

> - The MRO is entirely dependendent on the shape of the inheritance
>   graph, and not on incidental properties like the name of classes.
>
> Let's hear your justification for why breaking that condition is good.
>
> "I changed my class name from Spam to Eggs, and suddenly the inheritance
> relationships between my classes changed."
>
> "That's not a bug, that's a feature!!!"

Is it not true MI if the relationships change? Is that what you're
saying? What is "full MI"?

> - the inheritance model is consistent, monotonic and preserves local
>   precedence order (C3 linearization).
>
> Which of those three will you give up, and why is that a good thing?
>
> "In my class Spam, superclass A takes precedence over B, but when I
> subclass Spam, the precedence swaps and B comes before A."
>
> "That's not a bug, that's a feature!!!"

You keep asserting that, because something OBVIOUSLY would be a bad
thing for Python, it must not be "true multiple inheritance".

That's why you're being called out for the NTS fallacy. Your entire
definition of "full MI" is "Python 2.3+".

> > > If you exclude models of MI which are logically incoherent and
> > > inconsistent, (such as Python's prior to version 2.3), th

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

2022-04-15 Thread Chris Angelico
On Sat, 16 Apr 2022 at 14:33, Steven D'Aprano  wrote:
>
> On Sat, Apr 16, 2022 at 11:07:00AM +1000, Chris Angelico wrote:
>
> > > > 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.
>
> You are correct that virtual subclassing is still subclassing, but it
> doesn't provide inheritance.
>
> >>> from abc import ABC
> >>> class Parrot(ABC):
> ... def speak(self):
> ... print("Polly wants a cracker!")
> ...
> >>> @Parrot.register
> ... class Norwegian_Blue:
> ... pass
> ...
> >>> bird = Norwegian_Blue()
> >>> isinstance(bird, Parrot)
> True
> >>> bird.speak()
> Traceback (most recent call last):
>   File "", line 1, in 
> AttributeError: 'Norwegian_Blue' object has no attribute 'speak'

Yes. I would have to call this an abuse of a feature - you're
registering that a Norwegian Blue is a Parrot, without it being able
to do anything that a parrot should be able to. (Which I presume was
your intention, given your choice of examples.) You can claim that
it's a parrot all you like, and Python will happily reflect your
declaration when you ask if it's a parrot, but it's a pathological
case. It's like designing a class with no __str__ method, or one where
__add__ takes three parameters, or in any other way violates normal
expectations; you can use perfectly normal inheritance to derive from
object, but then you make changes so it no longer "behaves-like-a", ie
it violates Liskov.

> > What is "inheritance" if it isn't that is-a relationship? How do you
> > distinguish inheritance from delegation?
>
> Haven't you spent all of this thread quite happily distinguishing
> between using inheritance and composition/delegation until now? Okay.

Yes. I am asking you to now define the difference. My understanding
was that inheritance was defined by the "is-a" relationship, and
delegation was defined by other things. Now that you're claiming that
inheritance is NOT defined by an is-a, I want you to define it.

> Subclassing is, as you say, an "is-a" relationship. Whether you use
> virtual subclassing or actual subclassing, if you can say:
>
> issubclass(Norwegian_Blue, Parrot)
> isinstance(Norwegian_Blue(), Parrot)
>
> and get True for both of them, then Norwegian_Blue "is-a" Parrot.
>
> (Note that there is a technical difference between subclass and subtype,
> which I don't think is relevent to Python, but let's not go there.)
>
> Inheritance is a mechanism where a "child object" automatically acquires
> the properties and behaviors of some "parent object". In Python, that is
> handled by the interpreter when the child subclasses from the parent
> (but not in virtual subclassing).
>
> The critical thing is that in the absense of overloading or overriding,
> calling Norwegian_Blue().speak() will inherit the method defined in
> Parrot. We get that inheritance from real, but not virtual, subclassing.

Is it still inheritance if there needs to be a boatload of code to
make this happen? Because SOM/CORBA and the IDL want to have a word
with you.

In a good high-level language, there should normally be a convenient
way to do this without too much effort. But is that really essential
to it being inheritance?

As another example: In C++, a function accepting a pointer to a base
class can be given a parameter that points to a subclass. In the case
of multiple inheritance, this can actually mean that the pointer has
to change. So, two questions: (1) Is the fact that a function, not
defined outside in the class at all, accepts a pointer, part of the
behaviour of the class? And (2) If the compiler has to know "to turn a
pointer-to-X into a pointer-to-Y, add an offset of 16", is it still
retaining functionality?

You make a *lot* of assumptions based on Python, which simply don't
hold up in other languages, and then you assert that this is some kind
of absolute completeness.

> Composition provides a "has-a" relationship. For the sake of brevity, in
> simple terms (which may not be completely accurate, please don't nit-
> pick just for the sake of nit-picking), we use composition when we
> write:
>
> class Car:
> def __init__(self):
> self.engine = Engine()
>
> In this example, Cars are not Engines, but they have an Engine. Hence
> composition.
>
> Delegation provides a mechanism of code-sharing separate from
> inheritance, and often used instead of inheritance, or to compliment it.
> One object delegates to another object if the first explicitly calls the
> second:
>
> # self is a Car instance.
> self

[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] Subclassing and inheritance [was Re: Re: mro and super don't feel so pythonic]

2022-04-15 Thread Steven D'Aprano
On Sat, Apr 16, 2022 at 11:07:00AM +1000, Chris Angelico wrote:

> > > 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.

You are correct that virtual subclassing is still subclassing, but it 
doesn't provide inheritance.

>>> from abc import ABC
>>> class Parrot(ABC):
... def speak(self):
... print("Polly wants a cracker!")
...
>>> @Parrot.register
... class Norwegian_Blue:
... pass
...
>>> bird = Norwegian_Blue()
>>> isinstance(bird, Parrot)
True
>>> bird.speak()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'Norwegian_Blue' object has no attribute 'speak'


> What is "inheritance" if it isn't that is-a relationship? How do you
> distinguish inheritance from delegation?

Haven't you spent all of this thread quite happily distinguishing
between using inheritance and composition/delegation until now? Okay.

Subclassing is, as you say, an "is-a" relationship. Whether you use
virtual subclassing or actual subclassing, if you can say:

issubclass(Norwegian_Blue, Parrot)
isinstance(Norwegian_Blue(), Parrot)

and get True for both of them, then Norwegian_Blue "is-a" Parrot.

(Note that there is a technical difference between subclass and subtype,
which I don't think is relevent to Python, but let's not go there.)

Inheritance is a mechanism where a "child object" automatically acquires
the properties and behaviors of some "parent object". In Python, that is
handled by the interpreter when the child subclasses from the parent
(but not in virtual subclassing).

The critical thing is that in the absense of overloading or overriding,
calling Norwegian_Blue().speak() will inherit the method defined in
Parrot. We get that inheritance from real, but not virtual, subclassing.

Composition provides a "has-a" relationship. For the sake of brevity, in 
simple terms (which may not be completely accurate, please don't nit- 
pick just for the sake of nit-picking), we use composition when we 
write:

class Car:
def __init__(self):
self.engine = Engine()

In this example, Cars are not Engines, but they have an Engine. Hence
composition.

Delegation provides a mechanism of code-sharing separate from 
inheritance, and often used instead of inheritance, or to compliment it. 
One object delegates to another object if the first explicitly calls the 
second:

# self is a Car instance.
self.engine.start()

Delegation and composition often go together, but they don't necessarily
have to. One can delegate to an object "outside" of the class, although
that technique is not often used in Python.

But broadly speaking, if your instance uses:

super().method()

that's an inheritance call. (It is only needed when you overload 
method.) If you write something like:

SomeClass.method(self)

that's delegation.

Objects can delegate to anything they like, but if they delegate to a
superclass, we might call it inheritance even though it lacks the
property of being automatically handled by the interpreter. So one might
loosely say that inheritance is a special case of delegation.

Note that in languages without any form of super() or "next_class" or
whatever you call it, that sort of manual delegation may be the only way
to overload an inherited method.


> Is inheritance only a thing
> if it happens on the line of code that says "class X"? (Not the case
> in Pike.)

I don't think the syntax is important. You could say:

@inherits_from(Parrot)
class Norwegian_Blue:
pass

if you prefer. Defining the decorator is left as an exercise.

I can't comment on Pike, since you haven't described how it behaves.

As I said, in some languages mixins define inheritance without
subclassing; in Python virtual subclasses define subclassing without
inheritance.


> Is inheritance only a thing if it happens as the class is
> first created? (Is the case with mixins.)

I don't understand what you mean here. Do you mean that mixins inject
their methods into the class at creation time, and then no longer are
referenced? That's not what happens in Python. Mixins use the same
method resolution mechanism as other superclasses, which means it
happens on demand, not at creation time.

>>> class Mixin:
... def method(self):
... print("Creation time")
...
>>> class Spam(Mixin):
... pass
...
>>> Mixin.method = lambda self: print("Call time")
>>> Spam().method()
Call time


-- 
Steve
___
Python-ideas mailing list -- python-ideas@python.org
To unsu

[Python-ideas] Conditions for a coherent MI relationship [was Re: Re: mro and super don't feel so pythonic]

2022-04-15 Thread Steven D'Aprano
On Sat, Apr 16, 2022 at 11:07:00AM +1000, 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.

Which conditions would you drop? There's not that many, really. Five. 
Six if you include the "no cycles" requirement for the DAG, which I 
think is so obviously necessary that it is barely worth mentioning.

The most subjective is the requirement for automatic conflict 
resolution. It is a legitimate design choice to give up automatic 
conflict resolution (that's what C++ and Eiffel do) but that would be a 
breaking change for Python.

So come on Chris, back up your disagreement with something objective, 
not just wishy-washy "anything might happen in the future!" nonsense.

No, not everything is possible. We're never going to discover a new odd 
number between 3 and 5, or that 7 isn't really prime, or that cats are 
actually a type of plant, or that Australia doesn't exist.

So be concrete: which of my preconditions do you want to challenge?

- The inheritance model automatically resolves conflicts.

As I said, it is a legitimate design choice to give that up, but it 
would be a breaking change for Python so we can rule it out.

In any case, languages without automatic conflict resolution do less 
than languages with them. (That might be a good thing.)


- The MRO is entirely dependendent on the shape of the inheritance
  graph, and not on incidental properties like the name of classes.

Let's hear your justification for why breaking that condition is good.

"I changed my class name from Spam to Eggs, and suddenly the inheritance 
relationships between my classes changed."

"That's not a bug, that's a feature!!!"


- the inheritance model is consistent, monotonic and preserves local
  precedence order (C3 linearization).

Which of those three will you give up, and why is that a good thing?

"In my class Spam, superclass A takes precedence over B, but when I 
subclass Spam, the precedence swaps and B comes before A."

"That's not a bug, that's a feature!!!"


> > 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?

Yes. Its a DAG of superclass/subclass relationships. There is only one 
way to draw that graph that is coherent.

This is like sorting. Of course people can develop new and faster sort 
algorithms which use less memory, but nobody is going to discover that 
all the old sort algorithms are wrong and 5 should come before 2.

We might discover better algorithms for linearizing the superclasses, we 
might even discover a bug in the C3 algorithm. But we aren't going to 
discover that having your inheritance relationships flip order when you 
subclass is good, or that the order of linearization should depend on 
the time of day, or that violating local precedence is a good thing.


> I don't know whether you're mistaken or utterly arrogant.

Do you think they are the only two choices? Are you such a contrarian 
that you refuse to even consider that I might be right?

I have never claimed to be omniscient. Of course I could be wrong. I may 
have been mislead, or misunderstood the state of the art.

If you have something more than just wishful thinking about what "might" 
be discovered in the future, please tell me. I welcome corrections which 
are objective and based on proven facts.


-- 
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/HX6TBTXKKFQAVZM6AJ6S6BDPB5R7PUM4/
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/