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
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?
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
someMethod method of SomeClass class
with (SomeClass methodDict at: #someMethod)Then, we invoke that method on a Person object
with valueWithReceiver:arguments: method.
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:Posted by Florent Guillaume on October 09, 2006 at 09:56 PM IST #
Nice and interesting blog entry though :-)
-- daniel
6+13=19
Posted by Daniel on October 11, 2006 at 10:52 PM IST #
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
Posted by A. Sundararajan on October 12, 2006 at 09:36 AM IST #