Oops, super() can't work!

Guido.van.Rossum@cwi.nl
Wed, 12 May 1993 09:33:13 +0200

I had a hunch about Jaap's super() method that it wouldn't work with
multiple nested levels of extending the same method. Now I have
proof. The problem occurs when A is a base class of B and B
is a base class of C, and each of B and C have a method with the same
name that extends their base class's version. Now if we have an
instance of C, the C version will call the B version alright, but the
call to super() in the B version will not retrieve the A version of
the method -- it will retrieve the B version again. This is because
even during execution of the B method, the type of self is still C.
See example after my signature.

A built-in super() function would have the same problem -- the
information about the current class is simply not available (and
Python's dynamic object model makes it even possible to have a
function being included as a method in two different classes!).

So I'll have to resort to my gut feeling about this: if you don't know
which base class's method you're overriding you don't know what you're
doing!

The only way to fix this would be to make the interpreter aware of the
class to which a method belongs, which would require a major
reorganization of the interpreter and code generator. How does
Smalltalk do this? I know that Simula has a "super" construct in the
language but there it is solved at compile time. In C++ you have to
name the base class explicitly, as in Python. I believe it's the same
in Modula-3 (from which I borrowed more than one idea for Python).

My only hope is that perhaps Steve Myale of U of Virginia has already
fixed this in his mods to eliminate self and introduce private and
public variables (and much more). Steve? (We'll need to discuss your
changes to the language on the list anyway, before they can become an
official part of it.)

--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl>

========================================================================
class A:
def meth(self):
print 'A.self(', self, ')'

class B(A):
def meth(self):
print 'B.self(', self, ')'
super(self, 'meth')()

class C(B):
def meth(self):
print 'C.self(', self, ')'
super(self, 'meth')()

def super(obj, name):
# Simplified version of Jaap's super(), for instances only!
sym = 'obj.'+name

try:
try:
func = eval(sym)
exec('del '+sym)
return eval('obj.'+name)
finally:
exec(sym+'=func')
except:
return eval('obj.'+name)

print 'test A:'
a = A()
a.meth()

print 'test B:'
b = B()
b.meth()

print 'test C:'
c = C()
c.meth()
========================================================================
test A:
A.self( <instance object at 100e74d0> )
test B:
B.self( <instance object at 100e74b0> )
B.self( <instance object at 100e74b0> )
B.self( <instance object at 100e74b0> )
B.self( <instance object at 100e74b0> )
.
.
.