super or not super?
On Wed, Jul 17, 2019 at 3:58 AM Ian Kelly <ian.g.kelly at gmail.com> wrote:
> On Tue, Jul 16, 2019 at 1:21 AM Chris Angelico <rosuav at gmail.com> wrote:
> > On Tue, Jul 16, 2019 at 3:32 PM Ian Kelly <ian.g.kelly at gmail.com> wrote:
> > >
> > > Just using super() is not enough. You need to take steps if you want to
> > > ensure that you class plays nicely with MI. For example, consider the
> > > following:
> > >
> > > class C1:
> > > def __init__(self, name):
> > > self._name = name
> > >
> > > class C2(C1):
> > > def __init__(self, name, value):
> > > super().__init__(name)
> > > self._value = value
> > >
> > > This usage of super is just fine for the single-inheritance shown here.
> > > there are two reasons why this cannot be neatly pulled into an MI
> > > hierarchy. Can you spot both of them?
> > Well, obviously it's violating LSP by changing the signature of
> > __init__, which means that you have to be aware of its position in the
> > hierarchy. If you want things to move around smoothly, you HAVE to
> > maintain a constant signature (which might mean using *args and/or
> > **kwargs cooperatively).
> That's pretty close to what I had in mind. Many people treat __init__ as a
> constructor (I know, it's not)
If you consider __new__ to be the constructor, and __init__ to be an
implementation detail of how the constructor initializes the object,
then it comes to the same thing anyway.
> and so long as you're following that
> doctrine it's not really an LSP violation. But anything else that gets
> worked into an MI hierarchy has to somehow be compatible with both of these
> method signatures while also adding whatever new parameters it needs, which
> is a problem. The usual advice for working with this is to use **kwargs
> cooperatively as you suggested. *args doesn't work as well because every
> class needs to know the absolute index of every positional parameter it's
> interested in, and you can't just trim off the end as you go since you
> don't know if the later arguments have been consumed yet. With **kwargs you
> can just pop arguments off the dict as you go.
Yeah, makes sense. I'd advocate a slightly weakened form of LSP-style
equivalence: the function signatures don't have to be *identical*, but
they do have to be built with compatibility in mind.