« December 2009
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 1106

Powered by Roller Weblogger.
« Java Integration:... | Main | JSR-223 script engin... »
20061009 Monday October 09, 2006

Calling overriden superclass method on subclass instance

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

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?

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



( Oct 09 2006, 11:18:18 AM IST ) Permalink Comments [3] del.icio.us | furl | simpy | slashdot | technorati | digg

Comments:

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

Posted by Florent Guillaume on October 09, 2006 at 09:56 PM IST #

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

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 #

Post a Comment:

Comments are closed for this entry.
Copyright (C) 2005, A. Sundararajan's Weblog