X

Sundararajan's Weblog

  • Java
    October 8, 2006

Calling overriden superclass method on subclass instance

Guest Author

With OO languages, we can call the superclass version of a overriden method
- but, only within the subclass methods. But, how about calling a overriden superclass method from outside the subclass?

You may think you could perhaps use reflection and call
specific superclass method on a subclass instance.
But, when you call a method by Method.invoke
(in Java) or send (in Ruby)
perform: (in Smalltalk) the subclass method is called. You may want to
refer to the javadoc for Method.invoke
which clearly states:

If the underlying method is an instance method, it is
invoked using dynamic method lookup as documented in The
Java Language Specification, Second Edition, section
15.12.4.4; in particular, overriding based on the runtime
type of the target object will occur.


Java Example

import java.lang.reflect.Method;
class Person {
public void greet() {
System.out.println("Person's greet");
}
}
class Employee extends Person {
public void greet() {
System.out.println("Employee's greet");
}
}
class Main {
public static void main(String[] args)
throws Exception {
// get the method object from Person class.
Method g = Person.class.getMethod("greet",
new Class[0]);
Employee e = new Employee();
// When "g" is invoked on an "Employee" object,
// the "Employee.greet" method is called.
g.invoke(e, null);
}
}

Now, back to same question at the start. How do we call
Person.greet on an employee object? It turns out that
is possible with Smalltalk. If you don't know Smalltalk,
you may skip the next section and goto Ruby section -- knowing
that it is possible with Smalltalk!

Smalltalk Example

I tried the following with
Squeak 3.8.


"Assume that Person and Employee are classes"
"greet methods of Person and Employee are below"
greet
Transcript show: 'Person''s hello'; cr.
greet
Transcript show: 'Employee's hello'; cr.

For completeness, here is the "file-out" of Person
and Employee classes:

Object subclass: #Person

instanceVariableNames: ''

classVariableNames: ''

poolDictionaries: ''

category: 'MyTest'!
!Person methodsFor: 'as yet unclassified' stamp: 'AS 10/9/2006 07:11'!
greet
Transcript show: 'Person''s Hello'; cr.! !
Person subclass: #Employee

instanceVariableNames: ''

classVariableNames: ''

poolDictionaries: ''

category: 'MyTest'!
!Employee methodsFor: 'as yet unclassified' stamp: 'AS 10/9/2006 07:12'!
greet
Transcript show: 'Employee''s Hello'; cr.! !

With the above code, you can do something like the following (in a workspace):

(Employee new) perform: #greet withArguments: (Array new:0) inSuperclass: Person.

So, perform:withArguments:inSuperclass: lets us call any superclass method on a subclass instance (even if that
method is overriden in subclass).

Ruby Example

It is possible to do the above with Ruby too. In Ruby, method
objects carry the receiver object. It is possible to
disassociate the receiver by unbind method and then re-associate the unbound method with another
object using bind
method.

It is possible to

  • create a superclass object
  • get method object from superclass object
  • unbind method from the superclass instance
  • (re-)bind it to a subclass object

Example:

class Person
def greet
puts "Person's Hello"
end
end
class Employee < Person
def greet
puts "Employee's Hello"
end
end
e = Employee.new
p = Person.new
# get greet method from Person instance
m = p.method(:greet)
# unbind greet from "p" and rebind it "e"
# and then call. So, you are calling
# Person.greet on an Employee instance.
um = m.unbind()
um.bind(e).call()

Note for the JRuby users: With JRuby 0.9.0 version,
the above "bind" call does not work. You get en error
that looks like:


org.jruby.exceptions.RaiseException: bind argument must be an instance of Person

When I looked at the JRuby 0.9.0 source (RubyUnboundMethod.java
- bind method), it had this comment:


// FIX replace type() == ... with isInstanceOf(...)

It turns out that this issue (
JRUBY-103)
has been fixed in JRuby 0.9.1.

Why Java does not allow this?

  • Java reflection API tries to stay close to the source language semantics as much as possible. You can't do this with source language - and hance can't do this with reflection as well. [Yes, I agree that inner classes are not reflected well]
  • There may be security implications. A subclass may make assumptions - by overriding a specific superclass method, a subclass author may assume user's will not be able to call the superclass (potentially unsafe) methods on subclass instances - though I am not aware of such dependency in JDK platform API.

Calling any method on any object!

Smalltalk allows us to call any method on any object! For
example, you can get method (CompiledMethod) object from
one class and call that on an object of unrelated (by
inheritance relation) class. For example, let us assume
SomeClass is defined as follows (file-out)


Object subclass: #SomeClass

instanceVariableNames: ''

classVariableNames: ''

poolDictionaries: ''

category: 'MyTest'!
!SomeClass methodsFor: 'as yet unclassified' stamp: 'AS 10/9/2006 10:14'!
someMethod
Transcript show: 'someMethod'; cr.! !

We can call the SomeClass.someMethod method on say a
Person instance: (Person is unrelated to SomeClass by
inheriatance)

(SomeClass methodDict at: #someMethod) valueWithReceiver: (Person new) arguments: nil
  • We get the CompiledMethod object corresponding
    to someMethod method of SomeClass class
    with (SomeClass methodDict at: #someMethod)Then, we invoke that method on a Person object
    with valueWithReceiver:arguments: method.

Join the discussion

Comments ( 3 )
  • Florent Guillaume Monday, October 9, 2006
    In python, you can simply do:
    class Person(object):
    def greet(self):
    print "Person's greet"
    class Employee(Person):
    def greet(self):
    print "Employee's greet"
    e = Employee()
    Person.greet(e)

    which prints:
    Person's greet
  • Daniel Wednesday, October 11, 2006
    This is MHO - and I'd be ready to be flamed for it ;-), but in my experience if you get to the point where you need to call the superclass implementation of a method from outside of a subclass, then you probably should start wondering whether your design isn't badly flawed...


    Nice and interesting blog entry though :-)

    -- daniel

    6+13=19
  • A. Sundararajan Wednesday, October 11, 2006

    Hi Daniel: Yes, I agree with you - calling overriden superclass method is abstraction breaking. May be, my opening statement of this blog entry could have been different.

    But, reflection APIs provide such abstraction breaking hooks - for example: setAccessible() method in java.lang.reflect API - which may be useful for meta-level programs (such as IDEs/debuggers, object inspectors, object serialization). So, calling overriden superclass method may be one such abstraction-breaking-but-may-be-useful-in-certain-rare-cases hook. For Smalltalk's case, I came across this doc: http://minnow.cc.gatech.edu/squeak/1956

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.