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 / November 2007

Tip: Looking for answers? Try searching our database.

Behavior of OO

Thread view: 
Philipp - 28 Nov 2007 08:20 GMT
Hello
I have a somewhat naive question about OO.

If you have two classes Fruit and Apple extends Fruit. You declare:
  Fruit f = new Fruit();
  Fruit a = new Apple();
  f.eat();
  a.eat();
   
if you call the method .eat() on f, you get the eat() from Fruit and if
you call eat() on a, you get the overriden eat() behavior in Apple.

On the other hand, if somewhere else, the following two methods are
defined:
public void makeJam(Fruit f){};
public void makeJam(Apple a){};

and you call makeJam(f) and makeJam(a), both times it's the
makeJam(Fruit) which is called.

So in one case, the runtime "knows" that the object is actually an Apple
although it was declared a Fruit, and makes a distinction by calling the
correct method. In the other case it does not make the distinction. (yes
I know I could check with instanceof and cast)

Why is this so? Is this a design choice in the language? Or is it for
performance reasons? Are there cases when having it the other way (ie.
chosing the method signature which best fits the arguments) would lead
to UB?

Thanks for your comments
Phil
Gordon Beaton - 28 Nov 2007 08:14 GMT
> On the other hand, if somewhere else, the following two methods are
> defined:
[quoted text clipped - 3 lines]
> and you call makeJam(f) and makeJam(a), both times it's the
> makeJam(Fruit) which is called.

No, the most specific one is called in each case, so both your methods
are used in this example and the rest of your questions are moot.

For a long discussion about this, see section 15.12 of the JLS:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12

In particular, see 15.12.2.5 Choosing the most specific method:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#301183

/gordon

--
Gordon Beaton - 28 Nov 2007 08:19 GMT
>> On the other hand, if somewhere else, the following two methods are
>> defined:
[quoted text clipped - 6 lines]
> No, the most specific one is called in each case, so both your methods
> are used in this example and the rest of your questions are moot.

Sorry I misread, and see now that you declared both reference types as
Fruit (which I conveniently cut from my response). Still, have a look
at JLS 15.12.

/gordon

--
Philipp - 28 Nov 2007 08:45 GMT
>> On the other hand, if somewhere else, the following two methods are
>> defined:
[quoted text clipped - 6 lines]
> No, the most specific one is called in each case, so both your methods
> are used in this example and the rest of your questions are moot.

I'm sorry, but this is not what happens in my test SSCCE:

// Fruit.java
public class Fruit {
  public void eat(){
    System.out.println("Eating a Fruit");
  }
  public static void makeJam(Fruit f){
    System.out.println("Making jam with Fruit");
  }
  public static void makeJam(Apple a){
    System.out.println("Making jam with Apple");
  }

  public static void main(String[] args) {
    Fruit f = new Fruit();
    Fruit a = new Apple();
    f.eat();
    a.eat();

    makeJam(f);
    makeJam(a);
  }
}

//  Apple.java
public class Apple extends Fruit {
  public void eat(){
    System.out.println("Eating an apple");
  }
}

--- Output ---
Eating a Fruit
Eating an apple
Making jam with Fruit
Making jam with Fruit

> For a long discussion about this, see section 15.12 of the JLS:
> http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12
>
> In particular, see 15.12.2.5 Choosing the most specific method:
> http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#301183

Thanks for the refs, I will look into this.

Best regards
  Phil
Gordon Beaton - 28 Nov 2007 08:47 GMT
>>> On the other hand, if somewhere else, the following two methods are
>>> defined:
[quoted text clipped - 8 lines]
>
> I'm sorry, but this is not what happens in my test SSCCE:

You're right, I had failed to notice your declarations when I posted
my original response (I posted a follow-up shortly afterwards).

>      Fruit f = new Fruit();
>      Fruit a = new Apple();
>      f.eat();
>      a.eat();

The fact that Apple.eat() gets invoked instead of Fruit.eat() is that
the reference type doesn't change anything about the object itself, it
only restricts your view of the object.

So if there were a method specific to Apple, you would be unable to
invoke it through the Fruit reference:

  a.makeCider(); // will not compile

Similarly, when you pass 'a' to makeJam() you get Fruit jam, not Apple
jam. By choosing to access the object with a Fruit reference instead
of Apple, you are saying "I choose to ignore the fact that this is an
Apple, I only see generic Fruit here".

/gordon

--
Owen Jacobson - 28 Nov 2007 08:49 GMT
> Hello
> I have a somewhat naive question about OO.
[quoted text clipped - 25 lines]
> chosing the method signature which best fits the arguments) would lead
> to UB?

It's a design choice of the Java language, inherited from its
predecessors (C++, Smalltalk, and various others).  Method virtual
dispatch is only performed against the implicit zeroth argument,
"this"; the remaining arguments' *static* types are used to determine,
at compile time, what the signature of the method to dispatch is.

There are languages that do multiple dispatch; Haskell does it via its
pattern-matching mechanism, but it's by no means the first.  Even the
Common Lisp Object System has support for multiple dispatch.

While I have no particular insight into why Java's design uses single-
dispatch from a technical standpoint, I do find it easier to read code
in single-dispatch object systems than code for multiple-dispatch
systems.  It's also a much more common system; for a language designed
for The Masses that makes it more likely any random programmer already
understands the method dispatch system before coming to Java.

There are times when multiple dispatch leads to nicer code.  The
Visitor pattern is a simplistic way to emulate multiple dispatch in a
single-dispatch language; it's all but unnecessary when you can match
calls to method bodies based on the dynamic types of the arguments,
for example.

-O
Mike Schilling - 28 Nov 2007 10:21 GMT
> Hello
> I have a somewhat naive question about OO.
[quoted text clipped - 25 lines]
> chosing the method signature which best fits the arguments) would lead
> to UB?

Java inherits this behavior from C++.  Stroustrup explains why C++ does this
in his _The Design and Evolution of C++_, the answer being that trying to
dispatch on multiple types (the type of "this" plus the types of one or more
arguments) is far  ore complicated and difficult to do efficiently than
dispatching based on just one type.  It can also leads to problems like the
folllowing:

Suppose there are three methods foo(Object, Object), foo(Object, String),
and foo(String, Object).  Which should be called, given

   Object o1 = "abc";
   Object o2 -= "def";
   foo(o1, o2);
Daniel Pitts - 28 Nov 2007 18:52 GMT
>> Hello
>> I have a somewhat naive question about OO.
[quoted text clipped - 39 lines]
>     Object o2 -= "def";
>     foo(o1, o2);

There was a thread about this just recently on comp.object

Often times the "workaround" in languages that don't dispatch that way
is to use the Visitor pattern. That way, the object itself is
responsible for the final version of the method invoked, so the
polymorphic behavior is preserved.

In general, I think it is often better to have the Apple handling any
difference in makeJam that might happen simply because the Fruit is an
Apple.  Sometimes that solution isn't feasible, but its been my
experience that it /often/ is.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

George Neuner - 29 Nov 2007 00:12 GMT
>> ... in one case, the runtime "knows" that the object is actually an
>> Apple although it was declared a Fruit, and makes a distinction by
[quoted text clipped - 11 lines]
>arguments) is far  ore complicated and difficult to do efficiently than
>dispatching based on just one type.

Multimethod dispatch isn't difficult and it can be implemented quite
efficiently - but whereas single dispatch can be O(1) or O(d) in the
_d_epth of the class tree, multimethod dispatch is O(pt) or O(ptd) in
the number of _p_arameters, _t_ypes/classes and _d_epths of the class
trees.

The most common approach to multimethod dispatch seems to be a
discrimination tree:

if (param1 is typeA)
  if (param2 is typeX)
    :
  else
  if (param2 is typeY)
    :
  else
    :
else
if (param1 is typeB)
  :
else
  :

If the runtime data is organized properly, it is possible to have O(1)
type checks even with multiple inheritance.  It may not be necessary
to check all the parameters - each test must reduce the set of
possible matches (eventually to one) and a parameter which has the
same type in all the remaining overloads has no discriminating value.
And parameters do not need to be checked in order - the tree can be
arranged so that parameters with the most discriminating value are
checked first.

Java and C++ already perform this kind of discrimination to decide
which overloaded function to call, but the decision is made at compile
time using the parameter's static types.

Lisp generates code for multimethod dispatch at runtime (at the first
call) because Lisp allows runtime modification of classes and runtime
redefinition of methods - a new dispatch tree must be constructed for
a multimethod if any of the classes or overloaded methods involved are
changed.  However, Haskell and ML, which don't allow runtime
modification of methods or classes construct their dispatch code at
compile time.

Studies of multimethod use have shown that there are only a few
parameters and types involved in a typical dispatch so the
discrimination tree is usually quite shallow.

George
--
for email reply remove "/" from address
Stefan Ram - 28 Nov 2007 13:33 GMT
>you call makeJam(f) and makeJam(a), both times it's the
>makeJam(Fruit) which is called.

 Yes. But this might not have to do with »OO«
 - it is a property of the programming language Java.

>Why is this so?

 Because you have chosen Jave as a programming language.
 You could have chosen another language with another behavior.

>Is this a design choice in the language?

 Yes.

>Or is it for performance reasons?

 An alternative is »multiple dispatch«, which might introduce
 both performance problems (I am not sure about this) and also
 other problems of call semantics.

http://en.wikipedia.org/wiki/Multiple_dispatch
Joe Attardi - 28 Nov 2007 16:11 GMT
>   Fruit f = new Fruit();
>   Fruit a = new Apple();
[quoted text clipped - 3 lines]
> and you call makeJam(f) and makeJam(a), both times it's the
> makeJam(Fruit) which is called.

As some others have already pointed out, it's because f and a are both
references to Fruit. If you want makeJam(a) to call the makeJam(Fruit)
method, you can explicitly cast it as an Apple:

makeJam((Apple) a);
Mark Space - 29 Nov 2007 01:44 GMT
> On the other hand, if somewhere else, the following two methods are
> defined:
> public void makeJam(Fruit f){};
> public void makeJam(Apple a){};

Meanwhile, on the third hand, if you had declared makeJam() as a method
of both Fruit and Apple, you could invoke it polymorphically.

class Fruit {
   makeJam() {
   }
}
// Same for Apple
f.makeJam();
a.makeJam();
Roedy Green - 29 Nov 2007 03:44 GMT
>and you call makeJam(f) and makeJam(a), both times it's the
>makeJam(Fruit) which is called.

nope. Java  will use the most specific overloaded variant that it can
determine at compile time.  The restriction is the overloading choice
must be made from information available only at compile time. (In
contrast Nice decides at run time.  See
http://mindprod.com/jgloss/nice.html)

However, when you use a method call like this:

a.makeFruit().  Java can decide which version to use at RUN time based
on the type of a.

See http://mindprod.com/jgloss/gotchas.html#OVERRIDE
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com



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



©2008 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.