Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / January 2006

Tip: Looking for answers? Try searching our database.

Parametric covariance in class hierarchies

Thread view: 
Matthias Kaeppler - 22 Jan 2006 11:26 GMT
Hello,

can someone explain why in this code fragment always the base class
method is called?

class Base {
   void m(Object o) {...}
}

class Derived extends Base {
   void m(String s) {...}
}

...

public static void main(String[] argv) {
   Base b = new Derived();
   b.m("hello"); // calls Base::m
}

Of course, Base::m qualifies for the invocation with a string, but
Derived::m does as well (maybe even more). Is this some sort of "call
first match" principle, or is there more to it? Shouldn't the compiler
come to the conclusion that Derived::m is the better match for the
invocation of m()?

Thanks,
Matthias
Roedy Green - 22 Jan 2006 12:29 GMT
>can someone explain why in this code fragment always the base class
>method is called?

Let me start by first converting your snippet to as SSCCE so that
anyone skeptical of your claim can run the code:

public class Base
  {
  void m( Object o )
     {
     System.out.println( "base:" + o.toString ());
     }
  public static void main(String[] argv)
     {
     Base b = new Derived();
     b.m( "hello" ) ; // calls Base::m
     }
  }

class Derived extends Base
  {
  void m( String s )
     {
     System.out.println( "derived:" + s );
     }
  }

It indeed runs the base class version..  Why?

Java has to make its decision which method to use at COMPILE time.
This is not Nice that delays the decision to run time.  What
information does JavaC have?  Only that b is of type Base, and hence
has only ONE method m( Object). It has no choice. b is a Base,  Even
though for NOW you have set it to a Derived, there is no guarantee you
won't later set it to a pure Base.

If you changed your code to read:

Derived  b = new Derived();

Then you will run the better fit derived version.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.

Torkel Franzen - 22 Jan 2006 12:47 GMT
> Java has to make its decision which method to use at COMPILE time.

 More precisely, the compiler decides on the signature of the
method. If the class Derived had a method overriding m in Base, that
method would be used at runtime.
Roedy Green - 23 Jan 2006 09:01 GMT
>  More precisely, the compiler decides on the signature of the
>method. If the class Derived had a method overriding m in Base, that
>method would be used at runtime.
exactly. Java has compile time matching of methods with slightly
different signatures, but the same name. It has run time selecting of
methods with identical signature in subclasses.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.

Matthias Kaeppler - 22 Jan 2006 13:47 GMT
> Java has to make its decision which method to use at COMPILE time.
> This is not Nice that delays the decision to run time.  What
> information does JavaC have?  Only that b is of type Base, and hence
> has only ONE method m( Object). It has no choice. b is a Base,  Even
> though for NOW you have set it to a Derived, there is no guarantee you
> won't later set it to a pure Base.

Why? If I was to override m() in Derived, the decision would be made at
run-time, so why not decide at run-time here, too?

Regards,
Matthias
Stefan Schulz - 22 Jan 2006 19:49 GMT
> > Java has to make its decision which method to use at COMPILE time.
> > This is not Nice that delays the decision to run time.  What
[quoted text clipped - 5 lines]
> Why? If I was to override m() in Derived, the decision would be made at
> run-time, so why not decide at run-time here, too?

It does not make any decision which method to call at run-time. At
least not as far as the bytecode language is concerned. It will always
call void m(Object). However, what method is actually hiding behind the
entry for m(Object) in that objects method table may be different.
Chris Uppal - 22 Jan 2006 14:34 GMT
> class Base {
>     void m(Object o) {...}
[quoted text clipped - 3 lines]
>     void m(String s) {...}
> }

It may help to think of it this way.  The signature (types of the method
parameters) is part of the name of the method.  In the above code there is /no/
connection between the two methods called "m".  From the point of view of both
the compiler and the JVM the two methods are unrelated; exactly as unrelated as
if they were called m() and somethingElseEntirely().

> public static void main(String[] argv) {
>     Base b = new Derived();
>     b.m("hello"); // calls Base::m
> }

So when you call m() of an object statically declared to be of type Base, the
compiler generates bytecode which calls the method whose full name is:
   void m(Object)

When the JVM executes that code, it looks for a method with full name:
   void m(Object)
Since the only definition of a method with that full name is in Base, that's
the code that is called.  If Derived defined a method with that full name, then
the JVM would call that code instead.

The method with full name
   void m(String)
is simply irrelevant to all of this.  It has a different name so the JVM
doesn't even /consider/ it as a potential override of Base.m(Object).

Perhaps you think, or would prefer, that the JVM should take the dynamic type
of the parameter into account.  That's not unreasonable, and there are
languages which are defined to work like that (Lisp+CLOS for instance), but
that isn't how Java is defined.  In Java, the types of parameters are
considered only at compile time (in order to discover the full name of the
method to call), and the only type that is considered at runtime is the type of
"this".

Now, /why/ is that ?   The simple answer is "because that's how Java is
defined".  And -- at bottom -- there is no better reason.  As to why it was
defined like that, I don't know since I wasn't one of the designers (and I
haven't seen any comments on this issue by the designers).  If /I/ had been
designing an OO language, then I would do the same as the Java people did,
since that would minimise the runtime complexity of the semantics.  Java is a
dynamic language -- code can be loaded at runtime -- so I'd want to minimise
the interaction between loading new code (new classes) and the semantics of
/other/ code.  That would both  minimise the potential for confusing the
programmer and allow reasonably efficient implementations.  (As far as I know,
implementation techniques for method calls which resolve on parameter types,
and which do not require complicated lookup at runtime, all rely on of
whole-program analysis -- which is not feasible, or at least extremely
difficult, for Java).

   -- chris


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.