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 2008

Tip: Looking for answers? Try searching our database.

Why is dynamic polymorphism so useful?

Thread view: 
failure_to@yahoo.co.uk - 26 Dec 2007 01:26 GMT
hello

1) With dynamic polymorphism, calls to actual methods are resolved at
run time. So why is that so important?  Why is that so much better
than letting the compiler figure out which version of method to call
( based on the type of object being referred by reference variable )?
Result would still be the same ... if superclass variable referred to
child class object, then method of child class object would be
called!

2) Why isn't polymorphism also enabled for resolving calls to static
methods? Wouldn't there be some benefits by allowing that?

thank you
John W. Kennedy - 26 Dec 2007 03:17 GMT
> 1) With dynamic polymorphism, calls to actual methods are resolved at
> run time. So why is that so important?  Why is that so much better
[quoted text clipped - 3 lines]
> child class object, then method of child class object would be
> called!

> 2) Why isn't polymorphism also enabled for resolving calls to static
> methods? Wouldn't there be some benefits by allowing that?

These questions are, in the most literal meaning of the word, nonsense.
Try starting over with a better textbook, because the one you're
learning from isn't working. Honestly, I'm not trying to blow you off,
but your misunderstanding of the situation is so severe that I'd have to
write ten or twenty pages to create an answer for you -- and I'm not a
teacher.
Signature

John W. Kennedy
"The bright critics assembled in this volume will doubtless show, in
their sophisticated and ingenious new ways, that, just as /Pooh/ is
suffused with humanism, our humanism itself, at this late date, has
become full of /Pooh./"
  -- Frederick Crews.  "Postmodern Pooh", Preface

Lew - 26 Dec 2007 04:14 GMT
> hello
>
[quoted text clipped - 5 lines]
> child class object, then method of child class object would be
> called!

Actually, not, because at compile time the actual type of the object isn't known.

Look at it this way, there are two things in a program that have types: the
variable and the object.  Variables have compile-time type, objects have
run-time type.  Variables have scope, objects have lifetimes.  A variable can
go out of scope and disappear, but the object to which it pointed will live on.

Classic example:

List <String> messages = new ArrayList <String> ();

The variable 'messages' has only the compile-time type List <String>.  Thus it
only can invoke methods known to the interface.

The actual object has a run-time type of ArrayList.  This can change during
the program's lifetime:

 later:
   messages = new TreeList <String> ();

Now the run-time of the object has changed, perhaps in response to some
condition that doesn't always happen.

The compile-time type remains List.  No way the compiler can know ahead of
time that at certain times the dispatch for add() will have to follow a
different logic path.  That happens through the object, not the variable, at
run time, not compile time.

> 2) Why isn't polymorphism also enabled for resolving calls to static
> methods? Wouldn't there be some benefits by allowing that?

I don't remember them off the top of my head, perhaps it was from the Java
Language Specification (JLS) itself, but there are explanations you can
quickly google up.

My take on it is that you need an object to dispatch through, because it
depends on run-time type.  There is no object, nor run-time type to a class -
a class is a class.  All right, there is a kind of "object", but it's not at
all the same kind as the Java language means by an "object".

The class thing carries a bunch of information that pertain to that class.
There's nothing to dispatch through - no change in a class's state that says,
"OK, now we dispatch a method" - because there is no object of a subtype to
say, "Use my stuff."  There's just the class, itself.

So you call a static method Foo.doGlobalThing() - based on what would you say,
"dispatch to a subtype"?  Nothing, that's what.  You have to call the
doGlobalThing() in the Foo class - you can't know what subtype might be
intended.  The notion of an override has no referent, therefore no meaning.

Signature

Lew

Roedy Green - 26 Dec 2007 07:03 GMT
>1) With dynamic polymorphism, calls to actual methods are resolved at
>run time. So why is that so important?  Why is that so much better
[quoted text clipped - 3 lines]
>child class object, then method of child class object would be
>called!

You can get a more accurate match.  If a reference is an Object but
the object itself is a Rabbit, you can get the specialised Rabbit
method. Java does not know to use the specialised Rabbit method at
compile time.

There is extra overhead for runtime matching.  Even without it, you
can in your general method look for special cases and dispatch them to
more special methods.  To me, the problem does not come up often
enough for it to be worth the overhead.

Over time that tradeoff my change.  Lots of thing we would not dream
of doing before for programmer convenience become necessities with
sufficient RAM and CPU power.
Signature

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

Roedy Green - 26 Dec 2007 07:05 GMT
>2) Why isn't polymorphism also enabled for resolving calls to static
>methods? Wouldn't there be some benefits by allowing that?

You would need a reference that could refer to several different
class methods. That sounds a lot like a standard object pointer.  So
we are right back to ordinary instance methods.
Signature

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

Eric Sosman - 26 Dec 2007 14:10 GMT
> hello
>
[quoted text clipped - 5 lines]
> child class object, then method of child class object would be
> called!

    Please explain how the compiler can figure out which class'
method to call in

    Number n = (Math.random() < 0.5)
       ? new Integer(42) : new Double(42.0);
    String s = n.toString(); // Integer's toString, or Double's?

> 2) Why isn't polymorphism also enabled for resolving calls to static
> methods? Wouldn't there be some benefits by allowing that?

    When calling a static method, what is the `this' object whose
actual nature would determine the method to be called?

Signature

Eric Sosman
esosman@ieee-dot-org.invalid

Wayne - 26 Dec 2007 19:46 GMT
>     Please explain how the compiler can figure out which class'
> method to call in
>
>     Number n = (Math.random() < 0.5)
>         ? new Integer(42) : new Double(42.0);
>     String s = n.toString(); // Integer's toString, or Double's?

The best way to learn is to write programs and examine the results.
Here I created foo.java:

class foo {
public static void main (String[]args) {
 Number n = (Math.random() < 0.5)
       ? new Integer(42) : new Double(42.0);
 String s = n.toString();
}
}

Compiled with "javac foo.java", then running "javap -s -c foo"
produces:

Compiled from "foo.java"
class foo extends java.lang.Object{
foo();
 Signature: ()V
 Code:
  0:   aload_0
  1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
  4:   return

public static void main(java.lang.String[]);
 Signature: ([Ljava/lang/String;)V
 Code:
  0:   invokestatic    #2; //Method java/lang/Math.random:()D
  3:   ldc2_w  #3; //double 0.5d
  6:   dcmpg
  7:   ifge    26
  10:  new     #5; //class java/lang/Integer
  13:  dup
  14:  bipush  42
  16:  invokespecial   #6; //Method java/lang/Integer."<init>":(I)V
  19:  invokevirtual   #7; //Method java/lang/Integer.intValue:()I
  22:  i2d
  23:  goto    39
  26:  new     #8; //class java/lang/Double
  29:  dup
  30:  ldc2_w  #9; //double 42.0d
  33:  invokespecial   #11; //Method java/lang/Double."<init>":(D)V
  36:  invokevirtual   #12; //Method java/lang/Double.doubleValue:()D
  39:  invokestatic    #13; //Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
  42:  astore_1
  43:  aload_1
  44:  invokevirtual   #14; //Method java/lang/Object.toString:()Ljava/lang/String;
  47:  astore_2
  48:  return

}

===================================================

Even if you don't understand all of the JVM instructions you should be
able to follow this code: call Math.random, compare the result to 0.5,
if less then create a new Integer (lines 10-23), else create a new
Double (lines 26-38).  The value is converted to a String in lines 39-47.
It should be clear from line 39 the type of the expression you questioned
is...irrelevant!  Note the "i2d" instruction on line 22.  The compiler
is pulling the primitive int from the Integer (line 19), converting to a
double (line 22).  On the other hand, if a Double is created, its value
is extracted to a primitive (line 36).

Then in either case a third object, a Double, is created from that
double (line 39).  However the compiler invokes Object.toString, not
Double.toString (line 44) for reasons that elude me; perhaps an
optimizing compiler would use the more specific method.

When in doubt you can check the JVM specs (2nd ed is available
on-line).  Playing around like this is a terrific way to learn.

>     When calling a static method, what is the `this' object whose
> actual nature would determine the method to be called?

The keyword "this" is normally bound to the Object reference the
method is invoked on.  But for static methods, "this" keyword isn't
set at all and can't be used.

A mental model can simplify your thinking here (even if it is incorrect).
Every class is represented by an Object, created in a special way by the
ClassLoader, of type java.lang.Class.  You can think of any methods
and fields declared as static as methods and fields of that class Object
(again, that's not really correct).  Thus, when you create a class Foo
and some Foo objects you also have a Class object named "Foo", where
the system keeps the Foo class static fields (a.k.a. "class variables")
and methods, along with the ability to create objects of type Foo.
So when you invoke a static method the "this" reference, if it existed,
would not refer to any Foo type object but rather to the Class object
named Foo.  Thus such a method has access to static fields and other
static methods, but this Class object named Foo doesn't contain any
instance methods or fields.  (This mental model is too simple to
explain how it really works but it should help with understanding
this one aspect of static versus instance.  Please don't shoot me.)

Consider the method main: when starting the JVM, you specify a
class, not a class and method.  The JVM will create the Class
object for the specified class but no other objects.  So only
a static method could be invoked at that time, which is why
the main method must be static.

While some languages only have (the equivalent of) instance fields
and methods, Java provides you the choice.  The annoying part
is that Java uses the same operator to access static and instance
fields and methods leading to some confusion.  No doubt keeping
the number of operators low(er) made the compilers easier to write.

So if you want per-object properties use instance variables ("fields").
If you want single "global" or "shared" properties use static
variables (or fields).  If you want polymorphism use instance methods.
If you don't and you don't need access to instance fields, use
static methods.

>From your post I'm guessing you question the wisdom of providing
non-polymorphic methods.  You are not alone but personally I often
find them useful, especially for collections of "utility" methods
that don't need access to any instance fields.  (Take a look at the
utility classes in java.lang and java.util packages.  You'll find
most of the methods of these classes are declared static.)

Hope this helps!

-Wayne
Lasse Reichstein Nielsen - 26 Dec 2007 22:01 GMT
> The best way to learn is to write programs and examine the results.
> Here I created foo.java:
[quoted text clipped - 9 lines]
> Compiled with "javac foo.java", then running "javap -s -c foo"
> produces:
...
> Note the "i2d" instruction on line 22.  The compiler
> is pulling the primitive int from the Integer (line 19), converting to a
> double (line 22).  On the other hand, if a Double is created, its value
> is extracted to a primitive (line 36).

I can see that the conditional expression caused some unexpected coercions.
Try this instead:

 Number n;
 if (Math.random() < 0.5) {
   n = new Integer(42):
 } else {
   n = new Double(42.0);
 }

or perhaps just

 Number n = (Math.random() < 0.5) ? (Number) new Integer(42)
                                  : (Number) new Doubler(42.0);

> Then in either case a third object, a Double, is created from that
> double (line 39).  However the compiler invokes Object.toString, not
> Double.toString (line 44) for reasons that elude me; perhaps an
> optimizing compiler would use the more specific method.

It calls Object.toString virtually, because that is the most specific
toString that exists on the Number class.

It would be possible to optimize, if an analysis showed that only
Double values would ever become that value of Number type
variable. That analysis would have to be absolutely certain, even in
the presence of multiple threads simultaneously fiddling with other
object's fields using reflection. A mistake in the analysis would make
it into the class file, and the JVM would have no chance of correcting
it. That is why most optimizations are better left for the runtime
HotSpot optimizer, since it can optimize based on what is actually
happening, and can backtrack and use the unoptimized version if
the optimziation enabling conditions change.

In some cases (e.g., the example using "if" above), you can't know at
compile time what type of object it will be, so no compiler optimization
is possible.

/L
Signature

Lasse Reichstein Nielsen  -  lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
 'Faith without judgement merely degrades the spirit divine.'

Lew - 26 Dec 2007 23:41 GMT
>> The best way to learn is to write programs and examine the results.
>> Here I created foo.java:
[quoted text clipped - 29 lines]
>   Number n = (Math.random() < 0.5) ? (Number) new Integer(42)
>                                    : (Number) new Doubler(42.0);

The important point being that the compiler can have no way of knowing which
result will pertain at run time.  No need to read assembler for that; it's
plenty clear from just the Java code.

Signature

Lew

Wayne - 27 Dec 2007 15:25 GMT
>>> The best way to learn is to write programs and examine the results.
>>> Here I created foo.java:
[quoted text clipped - 33 lines]
> which result will pertain at run time.  No need to read assembler for
> that; it's plenty clear from just the Java code.

Hmm.  Could someone post an SSCCE using standard Java classes,
where the polymorphism shows in the output of javap?  All my
attempts at using toString result in Object.toString method
being invoked.

-Wayne
Lew - 27 Dec 2007 15:44 GMT
> Hmm.  Could someone post an SSCCE using standard Java classes,
> where the polymorphism shows in the output of javap?  All my
> attempts at using toString result in Object.toString method
> being invoked.

Perhaps something like a Collection add() where the implementation is
ArrayList or LinkedList or TreeSet or HashSet, chosen at runtime?

Signature

Lew

Wayne - 27 Dec 2007 16:31 GMT
> Hmm.  Could someone post an SSCCE using standard Java classes,
> where the polymorphism shows in the output of javap?  All my
> attempts at using toString result in Object.toString method
> being invoked.

Or perhaps even better, is there a freely available debugger
(say in Netbeans or Eclipse) that can display an object's
vtable (or whatever its called in Java)?  And to save me
hours of learning what is that debugger's command(s) to
do that?

-Wayne
Tim Smith - 30 Dec 2007 07:24 GMT
> > I can see that the conditional expression caused some unexpected coercions.
> > Try this instead:
[quoted text clipped - 14 lines]
> result will pertain at run time.  No need to read assembler for that; it's
> plenty clear from just the Java code.

It depends on how sneaky the compiler wants to be.  If it notices that
this code is only called once, couldn't it generate the random number at
compile time, and then just compile the appropriate branch?

Signature

--Tim Smith

Patricia Shanahan - 30 Dec 2007 14:38 GMT
>>> I can see that the conditional expression caused some unexpected coercions.
>>> Try this instead:
[quoted text clipped - 18 lines]
> this code is only called once, couldn't it generate the random number at
> compile time, and then just compile the appropriate branch?

No, because the result of Math.random() depends on the time of the first
call, and the number of prior calls to it anywhere in the program,
including in code that is not available at compile time. I assume
Math.random() was used in the example to represent any method whose
result depends on run time data, and varies from call to call.

In any case, the compiler needs a strategy that will work for multiple
calls.

Patricia
Lew - 30 Dec 2007 16:09 GMT
Tim Smith wrote:
>> It depends on how sneaky the compiler wants to be.  If it notices that
>> this code is only called once, couldn't it generate the random number
>> at compile time, and then just compile the appropriate branch?

> No, because the result of Math.random() depends on the time of the first
> call, and the number of prior calls to it anywhere in the program,
[quoted text clipped - 4 lines]
> In any case, the compiler needs a strategy that will work for multiple
> calls.

Even conceptually the idea of pre-compiling a random result is repugnant.
What would that do to cryptography?

In fact, random() is supposed to depend on unknowable, future extrinsic
events, like the output of your system's entropy generator.  We should
understand its role as close to being truly random.  The "pseudo" in
"pseudorandom" isn't supposed to mean, "deterministic, decided before we even
deploy the program".  It's like the old math joke - any time I need a random
number I pick 17.

Signature

Lew

Arne Vajhøj - 30 Dec 2007 17:03 GMT
> Tim Smith wrote:
>>> It depends on how sneaky the compiler wants to be.  If it notices
[quoted text clipped - 19 lines]
> even deploy the program".  It's like the old math joke - any time I need
> a random number I pick 17.

You are not supposed to use Math.random or java.util.Random.* in
cryptography - java.security.SecureRandom exist to handle those
cases.

Arne
Tim Smith - 30 Dec 2007 20:14 GMT
> In fact, random() is supposed to depend on unknowable, future extrinsic
> events, like the output of your system's entropy generator.  We should
> understand its role as close to being truly random.  The "pseudo" in
> "pseudorandom" isn't supposed to mean, "deterministic, decided before we even
> deploy the program".  It's like the old math joke - any time I need a random
> number I pick 17.

You've confused java.util.Random with java.util.SecureRandom.  The
former, which is what Math.random() uses, is a linear congruential
generator.  It is deterministic and completely predicatable from the
current state.  No external events affect it.

(And if you don't know the current state, observing consecutive output
of the generator allows the state to be recovered.  That's why such
generators are completely unsuitable for cryptographic work.  They were
broken a very long time ago--I believe it is even mentioned in the first
edition of Knuth volume 3, to give an idea of how long ago they were
broken).

Linear contruential generators are OK where you care about are the
statistical properties of the output, and do not care about the
predictability of it.

Signature

--Tim Smith

Lew - 30 Dec 2007 20:22 GMT
>> In fact, random() is supposed to depend on unknowable, future extrinsic
>> events, like the output of your system's entropy generator.  We should
[quoted text clipped - 18 lines]
> statistical properties of the output, and do not care about the
> predictability of it.

Yes, well, now two people have corrected my statement here.  What I was
driving for and missed was that even regular random() or Random should have
those statistical properties.  Just returning "17" probably won't.

Signature

Lew

Lew - 30 Dec 2007 20:29 GMT
Tim Smith wrote:
>> You've confused java.util.Random with java.util.SecureRandom.  The
>> former, which is what Math.random() uses, is a linear congruential
>> generator.  It is deterministic and completely predicatable from the
>> current state.  No external events affect it.

As Patricia Shanahan's post pointed out, there is some dependence on
something, in the choice of seed for the no-arg constructor.  It's not the
same every time and one might not know the seed.

For the purposes of this thread, also as Patricia pointed out, the fact that
the seed is (likely) different each time obviates a compiler's ability to
predict it, or to turn it into a constant.  It might be cryptographically
hackable, but not in service of a compiler optimization.

Signature

Lew

Lasse Reichstein Nielsen - 30 Dec 2007 16:16 GMT
> It depends on how sneaky the compiler wants to be.  If it notices that
> this code is only called once, couldn't it generate the random number at
> compile time, and then just compile the appropriate branch?

It cannot tell that it is only called once. Apart from the undecidability
of the general problem, the compiler doesn't know how many times the
program will be run.

Also, Java is a dynamically linked language where the compiler doesn't
necessarily have the entire program at compile time. The class compiled
at one time might be combined with classes compiled at another time and
place, and the entire program should still work correctly.

/L
Signature

Lasse Reichstein Nielsen  -  lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
 'Faith without judgement merely degrades the spirit divine.'

Tim Smith - 30 Dec 2007 20:03 GMT
> > It depends on how sneaky the compiler wants to be.  If it notices that
> > this code is only called once, couldn't it generate the random number at
[quoted text clipped - 3 lines]
> of the general problem, the compiler doesn't know how many times the
> program will be run.

Why would it matter how many times the program is run?  I don't see
anything (although I didn't do a deep search) in the documentation of
Math.random() that says the first value returned across different runs
of the programs must satisfy any particular distribution requirements.

Signature

--Tim Smith

Patricia Shanahan - 30 Dec 2007 20:17 GMT
>>> It depends on how sneaky the compiler wants to be.  If it notices that
>>> this code is only called once, couldn't it generate the random number at
[quoted text clipped - 7 lines]
> Math.random() that says the first value returned across different runs
> of the programs must satisfy any particular distribution requirements.

The Math.random() documentation says "When this method is first called,
it creates a single new pseudorandom-number generator, exactly as if by
the expression

    new java.util.Random

This new pseudorandom-number generator is used thereafter for all calls
to this method and is used nowhere else."

The java.util.Random documentation says that the parameterless
constructor "sets the seed of the random number generator to a value
very likely to be distinct from any other invocation of this
constructor." The algorithms for generating the streams of numbers from
the seed are fully documented.

I don't see how a compile-time selection could conform to that contract,
because it would act as though seed were the same for every invokation
of the java.util.Random constructor.

Patricia
Tim Smith - 31 Dec 2007 04:37 GMT
> > Why would it matter how many times the program is run?  I don't see
> > anything (although I didn't do a deep search) in the documentation of
[quoted text clipped - 19 lines]
> because it would act as though seed were the same for every invokation
> of the java.util.Random constructor.

Is that talking about different invocations within a program, or across
all programs?  I see they've changed the documentation since 1.4.  In
1.4, it used the millisecond time as the seed, so two separate programs
starting at the same time could get the same seed.  The later
documentation just says very likely to be distinct and doesn't give
details.

Given that it is a 48 bit seed, if they do it at random, then about
every 16 million times, there would be a duplicate seed (birthday
paradox argument on 2^48).  If they initialize partially with random and
partly with something derived from time, collisions from programs
launched apart in time would be less likely, but among all being
launched near in time, they would be more likely.

Given a 48 bit seed, I'd be a bit surprised if they mean that it is is
very likely to be globally distinct.  I'd expect the problem they were
trying to address with a new seeding procedure was the problem of
invocations from within the same program getting the same seed.  Imagine
an adventure game, say, that wants to give each computer-controlled
character its own random generator (that makes debugging easier, as you
can reproduce the sequence) rather than have them all share one, and it
happens to initialize them all within the same millisecond.  That could
be a problem, so I can see that they'd want to fix that.

Anyway, it's a fun problem to think about.

Signature

--Tim Smith

Patricia Shanahan - 31 Dec 2007 05:13 GMT
>>> Why would it matter how many times the program is run?  I don't see
>>> anything (although I didn't do a deep search) in the documentation of
[quoted text clipped - 32 lines]
> launched apart in time would be less likely, but among all being
> launched near in time, they would be more likely.

The new initialization uses the sum of a long counter and
System.nanoTime(). I think it would be practically impossible to get
duplication within a single JVM.

I would accept something happening once in 2^48 times as "very
unlikely", but not something happening every time. Indeed, the use of
time seems pointless if the intent of the Random API is to allow it to
produce the same sequence for each run.

Patricia
Mark Rafn - 26 Dec 2007 23:08 GMT
Homework?  Hate to encourage posting your class questions, but these come up
occasionally to non-school seekers of language design.

>1) With dynamic polymorphism, calls to actual methods are resolved at
>run time. So why is that so important?  Why is that so much better
>than letting the compiler figure out which version of method to call
>( based on the type of object being referred by reference variable )?

1a) Because the compiler cannot know what the runtime environment will be, and
what class implementations will be loaded.

1b) The compiler DOES decide this.  Not the java->bytecode compiler, but the
bytecode->machine just-in-time compiler that implements the runtime.  And it
re-decides as things change.

>Result would still be the same ... if superclass variable referred to
>child class object, then method of child class object would be
>called!

It can change between compiliation and runtime.  Heck, it can change during
runtime.

>2) Why isn't polymorphism also enabled for resolving calls to static
>methods? Wouldn't there be some benefits by allowing that?

How would it work?  Static methods have no object reference, so there are
never multiple different possibilities.
--
Mark Rafn    dagon@dagon.net    <http://www.dagon.net/>
failure_to@yahoo.co.uk - 27 Dec 2007 23:27 GMT
hello

> Homework?  Hate to encourage posting your class questions, but these come up
> occasionally to non-school seekers of language design.
>
> Mark Rafn    da...@dagon.net    <http://www.dagon.net/>

Chances are you prob won't read this post, but still...

I'd appreciate if you don't assume too much about the nature of my
questions since people on this forum may start to believe you and
decide not to help me and then I'm f*****. At least this  way I can
get a fair chance of getting people to help me when I can't figure out
the stuff on my own. Try to see this from my perspective

BTW-I'm not in any school and thus I'm learning programming by myself
and for myself, and if I get stuck on some topic, this group is my
best chance ( contrary to your belief,  I don't have a professor I can
run to for help )

I hope I haven't offend you with my little rant, since that wasn't my
intention

thank you all for your kind help

cheers
Mark Rafn - 28 Dec 2007 00:16 GMT
>> Homework?  Hate to encourage posting your class questions, but these come up
>> occasionally to non-school seekers of language design.

>Chances are you prob won't read this post, but still...
>I'd appreciate if you don't assume too much about the nature of my

I usually read direct followups to my posts.  I didn't mean any offense,
and I did, in fact, both state that it might not be homework AND give my
answer.  Mostly I wanted to let folks know that it might NOT be homework, to
avoid the common "we don't answer homework" one-liners...

Anyway, what did you think of the answers?  Make sense?  Raise other
questions?
--
Mark Rafn    dagon@dagon.net    <http://www.dagon.net/>
failure_to@yahoo.co.uk - 28 Dec 2007 22:58 GMT
hello

* I must first point out that I realize ( even when I first started
this thread ) that with the help of polymorphism we can get a generic
interface  and thus don’t have to change a code  when new subclass is
introduced!

1) Now what is most bugging me about polymorphism is the following:

I also realize, that with polymorphism we can run a program and while
program is already running, we can introduce a totally new class ( let
us call this new class N_C ) and thanx to polymorphism this program
may operate on instances of N_C without the need to recompile or even
without the need to restart this program.

But how to write a code for this program in such flexible way that
program will KNOW that new class is present and operate on it is
beyond me. Let me explain what I mean:

Say we have superclass A and bunch of subclasses ( all of them
override A’s method a1() ). Now somewhere in this program is a code
that calls a1() via reference variable ref_var:

* A ref_var; // here we define ref_var

* At some point in a program we assign to ref_var a reference to some
object ( this object might be of  class type A or one of its
subclasses )

*then we call ref_var.a1(); // which method to actually call is
resolved at runtime

Say we start this app and while app is already running, we write a new
class called N_C.
The already running  app has to be flexible enough to enable an object
of type N_C not only to be added to running app ( without even
restarting this app ), but to actually use this object.
But how do we do that? Let me explain it further:

Say this running app has an object of type B, where B is subclass of
A, and if I want ref_var to reference this object, then I do this by
writing in program code the following line:

B b       = new B():
ref_var   = b;

The above lines are hard coded into program. But how do we assign
ref_var a reference to object of type N_C, if we introduce this new
class to already running app --> somewhere in the program code the
following two lines would have to be written:

N_C n_c    = new N_C();
ref_ver    = n_c;

But problem is app is already running and we don’t want to stop this
app to write the above two new lines and yet we want this app to
somehow use this new object ( by assigning ref_var a reference to
n_c ). Now how can assign ref_var a reference to object of type N_C
without adding the above two lines into code ?

> Anyway, what did you think of the answers?  Make sense?  Raise other
> questions?
> --
> Mark Rafn    da...@dagon.net    <http://www.dagon.net/>

Perhaps I shouldn't say this, cos you went through so much trouble in
order to help me, but truth be told questions were a bit too technical
for me and even if I did somewhat understand what ( some of ) you were
saying, I didn’t understand why would arguments you provided prove
anything ( at least I didn’t find them to prove anything, but then
again, I'm not exactly ...). But I do know that in time ( when I get a
bit better in programming )  these answers will be of great value

I will give just a few examples:

>> 1) With dynamic polymorphism, calls to actual methods are
>> resolved at run time. So why is that so important?  Why is that
[quoted text clipped - 11 lines]
>Rabbit method. Java does not know to use the specialised Rabbit
>method at compile time.

Why couldn’t java know at compile time what to do with rabbit method?
Perhaps because creators of Java decided compiler doesn’t have to know
that, since, afteral, they were gonna implement dynamic binding, or is
it in general not possible for compiler to know that, even if creators
of Java wanted for compiler to know that?

> Please explain how the compiler can figure out which class'
> method to call in
>        Number n = (Math.random() < 0.5)
>            ? new Integer(42) : new Double(42.0);
>        String s = n.toString(); // Integer's toString, or Double's?

I don’t understand how this proves anything? Perhaps if this was done
at compile time, then internally ( I’m talking out of my arse now )
there could be another

if ( n is integer then call n.toString(Integer n) )
 else ( else if n is double then call n.toString( Double n ) )

statement that enable the compiler to "call" the appropriate method.

>>Result would still be the same ... if superclass variable
>>referred to child class object, then method of child class
>>object would be called!
>
>It can change between compiliation and runtime.  Heck, it can
>change during runtime.

What can change?

BTW - I do realize that compiler can’t resolve method calls due to
Java ability of introducing new classes to program ( without the need
to recompile a program ) thus compiler has no way of knowing what
classes may be added to program in the future ( the questions I
originally asked ignored on purpose this Java ability )!

uh
Lew - 29 Dec 2007 01:56 GMT
> I also realize, that with polymorphism we can run a program and while
> program is already running, we can introduce a totally new class ( let
[quoted text clipped - 5 lines]
> program will KNOW that new class is present and operate on it is
> beyond me.

Java has basically three ways to accomplish this: classloaders, reflection and
the debugger API.

All three are advanced topics.  Let me give just the briefest summary.

Classloaders can be directed to reach out to a known source and load the
bytecode for a class while the program is running.

Reflection lets a program retrieve instances from classes not known until run
time, perhaps ones that have been retrieved through a custom classloader.

The debugger API has hooks that let a program substitute different class
versions for each other while the program is running.

Didn't catch who said:
>> You can get a more accurate match.  If a reference is an Object
>> but the object itself is a Rabbit, you can get the specialised
>> Rabbit method. Java does not know to use the specialised Rabbit
>> method at compile time.

> Why couldn’t java know at compile time what to do with rabbit method?

That's "Java", not "java".

This was explained a few times in this thread.  It's not what "Java" knows,
it's what the variable type is, that determines what methods the variable can
call.  Remember from upthread that variables have compile-time type, objects
have run-time type.

> Perhaps because creators of Java decided compiler doesn’t have to know
> that, since, afteral, they were gonna implement dynamic binding, or is
> it in general not possible for compiler to know that, even if creators
> of Java wanted for compiler to know that?

No need to get religious - the creators of Java have nothing to do with this.

Java is defined by a set of rules, and those rules determine the behavior.
The key is to remember that variables have only compile-time type - objects
have run-time type.  The variable knows how to ask for something in the
compile-time type, e.g., "x.run()" for a variable "x" of type "Runnable".
Since there is no information in the compiler about the run-time type of the
actual object, it is only valid to say that "x" calls its "run()" method.  The
actual object at run time will pick up the request for a "run()" and simply
use its own method to do it.  That's all.

>> Please explain how the compiler can figure out which class'
>> method to call in
[quoted text clipped - 5 lines]
> at compile time, then internally ( I’m talking out of my arse now )
> there could be another

The whole point is that the compiler only knows that the variable 'n' is a
'Number'.  No more is needed, actually.

At run time, the object will pick up the call to toString(), and use its own
version of toString() to fulfill the call, is all.

> if ( n is integer then call n.toString(Integer n) )
>   else ( else if n is double then call n.toString( Double n ) )

No need for that when the object itself already knows how to toString()
itself.  It's called separation of concerns, and encapsulation.  The calling
method doesn't need to care about the details - it just trusts the object to
call its own method on its own.

> statement that enable the compiler to "call" the appropriate method.

Compilers don't call methods, objects do.  Compilers just tell the object
which method to call.

>>> Result would still be the same ... if superclass variable
>>> referred to child class object, then method of child class
>>> object would be called!

How would a compiler know what object is in play in the future?

>> It can change between compiliation and runtime.  Heck, it can
>> change during runtime.
>
> What can change?

The object that is asked to perform the method can change.

> BTW - I do realize that compiler can’t resolve method calls due to
> Java ability of introducing new classes to program ( without the need
> to recompile a program )迳 thus compiler has no way of knowing what
> classes may be added to program in the future ( the questions I
> originally asked ignored on purpose this Java ability )!

This has nothing to do with polymorphism.  Polymorphism is simply that the
object decides for itself how to execute a method.

Signature

Lew

twerpinator@gmail.com - 31 Dec 2007 19:05 GMT
> failure...@yahoo.co.uk wrote:
> > I also realize, that with polymorphism we can run a program and while
[quoted text clipped - 9 lines]
> Java has basically three ways to accomplish this: classloaders, reflection and
> the debugger API.

And one method that is relatively "nice", using a fairly simple subset
of reflection, is serialization.

Say you have a plugin architecture with, say, pluggable codecs. You
employ the strategy pattern and create a Codec interface that has
encode() and decode() methods, among others, and supply some
implementations. But you also provide code that runs at startup or
when a user picks "Scan for plugins" from a menu that looks in a /
plugins directory someplace looking for ".codec" files, which are
actually serialized instances of Codec objects. It reads these one by
one with an ObjectInputStream and casts each to Codec; if a
ClassCastException is thrown, it's ignored and so is the object that
was loaded; same if any of the various serialization exceptions or
IOExceptions are thrown. NoClassDefFound? Discard.
ObjectStreamException? Discard. The surviving objects are added to the
collection of Codec objects the program maintains. Perhaps there's an
initialize() method on these, and the ones that are newly added (using
a Set allows detecting which are really new) get this run, adding
particular "Save As" options that go through their respective encode()
methods. Perhaps the program tries to decode files opened with "Open"
by invoking each one's "decode()" in turn until one of them returns
something other than null (or doesn't throw some exception); the new
ones now get a crack at decoding any opened file.

This requires, on the programmer's part, no nastier reflection code
than code to deserialize objects (and, in some SDK somewhere, to
serialize them so plugins can be made). A plugin's installation
requires only that some .class files (perhaps wrapped in a .jar) go
into the application's classpath and a .codec file go in the
application's plugins directory. Likely that plugins directory is on
the app's class path and contains the plugin classes as well.

A .codec missing a needed .class will result in some sort of
deserialization exception; that particular one should probably trigger
a warning to the user, since it likely resulted from a sloppy
installation. A user adding a plugin and getting a silent failure of
anything new to appear in the program's menus will be much less able
to diagnose and fix the problem than one told that they forgot to
install one of the plugin's files (or the plugin's installer did).

It shouldn't be hard to generalize the above far beyond codecs to all
sorts of other plugin architectures.

The dynamic polymorphism here is of course in any of the instance
method calls through the Codec interface, and here can call code added
while the program is already running.
Owen Jacobson - 31 Dec 2007 21:47 GMT
On Dec 31, 11:05 am, twerpina...@gmail.com wrote:

> > failure...@yahoo.co.uk wrote:
> > > I also realize, that with polymorphism we can run a program and while
[quoted text clipped - 41 lines]
> application's plugins directory. Likely that plugins directory is on
> the app's class path and contains the plugin classes as well.

The Java Beans specification uses the extension ".ser" for this and
provides some hooks in the .jar format and java.beans API for finding
and loading serialized bean instances.  See sections 10.3 and 11.8 of
the spec:
 <http://java.sun.com/products/javabeans/docs/spec.html>

and the related API docs:
<http://java.sun.com/javase/6/docs/api/java/beans/
Beans.html#instantiate(java.lang.ClassLoader,%20java.lang.String)>

and the Java-Bean MANIFEST.MF entry described in:
 <http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html>

-o
nebulous99@gmail.com - 03 Jan 2008 20:02 GMT
> The Java Beans specification uses the extension ".ser" for this and
> provides some hooks in the .jar format and java.beans API for finding
[quoted text clipped - 5 lines]
>  <http://java.sun.com/javase/6/docs/api/java/beans/
> Beans.html#instantiate(java.lang.ClassLoader,%20java.lang.String)>

Haven't bothered with Beans much, but it sounds similar. Perhaps a bit
more complex to do/use but perhaps a bit more powerful in exchange; it
looks like you need to muck about explicitly with classloaders.
Patrick May - 29 Dec 2007 03:48 GMT
> 1) Now what is most bugging me about polymorphism is the following:
>
[quoted text clipped - 7 lines]
> program will KNOW that new class is present and operate on it is
> beyond me. Let me explain what I mean:

    Here's a simple example:

         http://www.spe.com/Chain_of_Responsibility.html

Does that help?

Regards,

Patrick

------------------------------------------------------------------------
S P Engineering, Inc.  | Large scale, mission-critical, distributed OO
                      | systems design and implementation.
         pjm@spe.com  | (C++, Java, Common Lisp, Jini, middleware, SOA)
Lew - 28 Dec 2007 00:23 GMT
> At least this  way I can
> get a fair chance of getting people to help me when I can't figure out
> the stuff on my own. Try to see this from my perspective

You will note that your post got many useful answers by several people who
made no overt assumptions about your purpose.

Signature

Lew



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.