🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.jbuilder.java.language
Article #17860

Re: Double dispatching technique (Visitor pattern)

#17860
From: John P. McGrath
Date: Mon, 14 Sep 1998 00:00
167 lines
5345 bytes
Edoardo:

The behavior you are seeing is the correct behavior.

When the compiler compiles a method call, it determines the signature of 
the method to be called, based on the types of the arguments specified in 
the call, and stores the method signature in the class file.  So these 
lines of code generate the method calls in the comments.

1)  // Call print(Fruit) on a Main object.
    Fruit fruit = new Fruit();
    print(fruit);

2)  // Call print(Apple) on a Main object.
    Apple apple = new Apple();
    print(apple);

3)  // Call print(Fruit) on a Main object.
    Fruit fruit2 = new Apple();
    print(fruit2);

4)  // Call print() on a Fruit object.
    void print(Fruit aFruit) {
       aFruit.print();
    }

5)  // Call print() on an Apple object.
    void print(Apple anApple) {
       anApple.print();
    }

When the JVM interprets these method calls, it calls the method with the 
specified signature for the run-time object whose method is being called.  

In cases 1, 2, and 3, the object is a Main object.  In case 5, the object 
is an Apple object.  Since there are no subclasses of Main and Apple, it 
is obvious which is called.  Of course, this assumes that there are no 
other classes involved that extend Main or Apple.

In case 4, however, the class of the object receiving the print() call 
could be either a Fruit or of a sub-class of Fruit (i.e. Apple).  The 
method being called depends on the object receiving the method call.  So 
this could call either Fruit.print() or Apple.print().  But no matter 
what type of object is having its method invoked, we know at compile time 
that the print() method will be called.  The signature of the method to 
be called was determined at compile time.

So the short answer is, Java does not directly support the double 
dispatch that you are looking for.  If you want to, you can implement 
double dispatching using the Reflection mechanism.  You would have to 
look up all of the available methods for the target object and all of its 
superclasses, and determine which method matched your call best.

In a simple case, such as your example code, this might be relatively 
easy.  But lets make it just a little more complicated.  What if there 
were more than one argument?  Say you had the following call:

	eat( new Apple(), new Apple() );

... and the target object had two print methods:

	eat( Apple apple, Fruit fruit );
	eat( Fruit fruit, Apple apple );

Which method would you want to be called in this case?

Also consider the additional run-time overhead that would be required on 
every method call in order to support double dispatch.  It would slow 
down all Java programs, not just those that used the facility.

--
Regards,

John P. McGrath
<mcgrath@enter.net>
<jpm@nscs.fast.net>


Edoardo Comar <comar@tecnest.it> wrote:
> Does the double dispatching technique of GOF's Visitor pattern not always
> work in Java ?
> 
> I saw that if you have an overloaded method of which a version take as an
> argument an object of class A,
> and another takes an object of class B which extends A, if you invoke it
> with a reference of type A which points to
> a class B object, the JVM selects the first version (the one which declares
> an instance of class A as its parameter).
> 
> Is this behavior correct ?
> 
> If you like, play with this sample of mine.
> =======
> package edotest;
> 
> public class Fruit
> {
>   public void print()     // (3)
>   {
>     System.out.println("Fruit");
>   }
> }
> =======
> package edotest;
> 
> public class Apple extends Fruit
> {
>   public void print()  // (4)
>   {
>     System.out.println("Apple");
>   }
> }
> =======
> package edotest;
> 
> public class Main
> {
>   Fruit fruit = new Fruit();
>   Apple apple = new Apple();
>   Fruit fruit2 = new Apple();
> 
>   public static void main(String[] args)
>   {
>     Main main = new Main();
>     main.test();
>   }
> 
> 
>   void test()
>   {
>     print(fruit);   // invokes (1 + 3 )
>     print(apple); // invokes (2+ 4 )
>     print(fruit2); // invokes (1 + 4 )
>   }
> 
> 
>   void print(Fruit aFruit)        // (1)
>   {
>     System.out.print("Main.print(Fruit aFruit) : ");
>     aFruit.print();
>   }
> 
> 
>   void print(Apple anApple) // (2)
>   {
>     System.out.print("Main.print(Apple anApple) : ");
>     anApple.print();
>   }
> 
> }
> =======
> 
> 
> bye,
> Edo.
> 
> ing. Edoardo Comar
> <comar@tecnest.it>
> Tecnest S.r.l
> via Tullio, 11/13 - 33100 Udine Italy
> ph. +39 432 511550
> fax +39 432 508725
> --------
> <e.comar@go.nettuno.it> (home email)
> PGP RSA key on keyservers  http://wwwkeys.pgp.net
> key ID 29365395  created 1994/11/03
> fingerprint = 5E 10 E1 46 22 35 84 3D  3F 57 E0 35 BE 5C 1E A7
Technical Details
Message-ID: <MPG.106681ecc7d3db84989695@forums.inprise.com>
Path: arc1-ca.pugleaf.net!unknown!not-for-mail
References: <6sjh8m$eq419@forums.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f74b3,107ec690fdf39b4a
X-Google-Attributes: gidf74b3,public
From: mcgrath@enter.net (John P. McGrath)
Subject: Re: Double dispatching technique (Visitor pattern)
Date: 1998/09/14
Message-ID: <MPG.106681ecc7d3db84989695@forums.inprise.com>
X-Deja-AN: 390902607
References: <6sjh8m$eq419@forums.borland.com>
Organization: Software Consulting Services
Newsgroups: borland.public.jbuilder.java.language