On Sun, Apr 03, 2022 at 03:09:18PM -0000, malmiteria  wrote:

> feature 1 (of super alone): proxying the parent.
> What most people think super does (and expect it to do):
> it allows to call method from *the* (most people don't think of 
> multiple inheritance) parent.

For single inheritance, that is exactly what it does, and there is no 
problem. Just use super() and it Just Works.

If you disagree, then please show me an example of *single* inheritance 
where super does not do the right thing, where each class simply calls 
its direct parent.


> It can be used by working around MRO to proxy any parent directly.

I don't know what you mean by this. Why are you "working around" the 
MRO? If your class is skipping some of its superclasses, then it is 
either broken, or you shouldn't be using inheritance for the 
relationships between the classes.


> feature 2 (of super + MRO): sideway specialization / mixins

This is just a form of multiple inheritance where the mixins are not 
designed to be instantiated themselves.


> feature 3 (of super + MRO): dependency injection / inheritance tree 
> alteration

I don't know what you mean by dependency injection here. Dependency 
injection is one of those Design Patterns beloved by Java developers who 
over-engineer it into something complicated, but in Python is so trivial 
that it barely deserves a name.

To quote James Shore:

“Dependency Injection” is a 25-dollar term for a 5-cent concept.

https://www.jamesshore.com/v2/blog/2006/dependency-injection-demystified

Inheritance tree modification... I think that means you want to copy a 
class hierarchy, but with changes?

Again, this sounds like inheritance is the wrong tool here. Nnot 
everything is an inheritance relationship.


> feature 4 (of MRO alone): method resolution

This is the one and only thing that super() if for. Well to be precise, 
its not just methods, but any attributes.


> "feature" 5 : diamond problem.

The diamond problem is a feature of multiple inheritance with diamonds. 
super() can't solve it in the fully general case because there is no 
general solution.


> What motivated me first here was the few problems with the feature 1 
> (proxying the parent)

What problems? Here you are talking about *the* parent, so we have 
single inheritance:

```
class Parent:
    def method(self):
        print("the parent does stuff")


class Child(Parent):
    def method(self):
        ...  # what problems with super?

```

Please show me what problems you have with super in that simple case of 
a class with only a single parent class.



[...]
> 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()
> 
> class HalfBreed(ProudGobelin, CorrupteGobelin):
>     def scream(self):
>         # 50% chance to call ProudGobelin scream, 50% chance to call 
> CorruptedGobelin scream
> ```
> 
> when writing down the class HalfBreed, we expect the behavior of 
> HalfBreed().scream() to be one of its parent behavior, selected at 
> random with 50% chance each.

Okay.


> with the use of super, it could look like that, intuitively

Not it can't. This is wrong. You have misunderstood what super does.

What you are doing in this broken class below:

> class HalfBreed(ProudGobelin, CorrupteGobelin):
>     def scream(self):
>         if random.choices([True, False]):
>             super(HalfBreed, self).scream()
>         else:
>             super(ProudGobelin, self).scream()

is to try (and fail!) to use inheritance for behaviour which needs to be 
modelled by delegation.

By definition, inheritance requires HalfBreed to call the methods of all 
three superclasses. (That is at least the definition used in Python, 
other languages may do differently.) If HalfBreed is not using the 
methods of all its superclasses, it is not really an inheritance 
relationship.


And you provide the right solution: delegation.

> class HalfBreed(ProudGobelin, CorrupteGobelin):
>     def scream(self):
>         if random.choices([True, False]):
>             ProudGobelin.scream(self)
>         else:
>             CorrupteGobelin.scream(self)

> Which is an option multiple of you pointed out to me.
> This options however is flawed in muliple ways, mainly because it 
> looses 3 of the 4 features i describe earlier.

>  - we lose the proxy feature, which to be fair, is aqueen to syntactic 
>  sugar. But this is still a feature loss.

How do you lose a feature you don't want? You don't want to call the 
parent classes' methods using inheritance. If you did, you would use 
super, and the HalfBreed would inherit from all three superclasses.

But you don't want that, do you do something else. Problem solved.


>  - we lose the sideway specialisation, coming from super's behavior, 
>  which, in this case, is the goal, so we're not complaining.

What sideway specialisation? You have no mixin classes here.

>  - we lose the possibility of class dependency injection, since today, 
>  it relies on a consistent use of super.

No it doesn't.

Dependency injection has nothing to do with 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/G53SN6VDYLA3VVFYZGG2HO7DDBQ7O45L/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to