Could Python supplant Java?

James J. Besemer jb at cascade-sys.com
Mon Aug 26 21:52:46 EDT 2002


Paul Foley wrote:

>On Fri, 23 Aug 2002 10:14:08 -0700, James J Besemer wrote:
>
>>Just Plain Wrong, certainly depends on what you're used to.
>>
>You mean if you're used to languages that do the wrong thing, you
>probably don't notice that it's wrong?  Doesn't make it any less
>wrong, though.
>
I meant it in the exact same same vein that Pythonistas say all the time 
about Python -- work around what you perceive to be a problem or 
limitation and after a while you'll get used to it and come to accept 
that it's not a problem.  I can see how the way C++ works in this case 
would be confusing for some, especially newbies, but it ceases to be a 
problem after you learn the language.

>No, that's completely irrelevant.  Casting, automatic or otherwise,
>really has nothing to do with it.
>
>If you used "virtual" it would work, regardless of any casts.
>
>You obviously didn't try it.  It won't do what you say it will.
>
You're right.  I was wrong about this, as I acknowledged earlier.

I actually did try it but I did the harder example first and forgot to 
remove 'virtual' for the simpler case.

FWIW, I blame this and other careless errors on the fact that I had been 
up for about 24 hours straight at the time.

>consider the possibility that if you
>knew it better, you might think it was more "Wrong".
>
Anything is possible but I don't think so.  

For it to work the way you expect requires a late binding model -- a 
table lookup for each access because nothing can be relied upon at 
compile time.  This is inconsistent with the whole design philosophy of 
C++, which fixes all name and type bindings at compile time.

For better or worse, the truly innovative thing about C++ to be that it 
offers most of the flexibility of other OOP languages (Polymorphism for 
example) while still providing a strong compile time type checking and 
binding of all symbolic references at link time.  That is OOP without 
the traditional runtime penalty.  Now maybe Stroustrup was barking up 
the wrong tree all the time striving to maintain these objectives (no GC 
either) but it's an certainly important accomplishment in the history of 
programming languages.  Borland's Delphi made similar strategic design 
decisions, so maybe it's not totally crazy.

The trade off is that your OOP application can run at machine speeds 
without all the considerable overhead doing dictionary hash table 
lookups for each name reference.

The difference is dramatic:

    http://cascade-sys.com/~jb/Pythonetics/callcost/index.htm

The 100X or 200X runtime penalty clearly illustrates the difference 
between early and late binding, IMO.

Now, whether the cost of the extra declarative burden (not to mention 
the other complexities of C++) are worth the runtime savings depends on 
your application.  In many cases it is a loss because it takes more 
programmer time ,which (in most cases) is way more valuable than 
computer time.  But sometimes the performance is worth the cost.  It's 
good to have the choice and it's good that you don't have to abandon OOP 
to reap the benefits.

>>Clearly we disagree on the definition of Polymorphism.  I think most authorities
>>agree that C++ has Polymorphism as demonstrated above.
>>
>C++ does have polymorphism, noone's denying that.  But what you
>demonstrated above is not it.  To get polymorphism in C++, you use
>"virtual".
>
Clearly we disagree and maybe we never will agree.

I've cited public 3rd party definitions previously and you've ignored 
them.  Here's SEVERAL MORE that support my broader view of Polymorphism 
(which expressly includes operator overloading).  

    http://whatis.techtarget.com/definition/0,,sid9_gci212803,00.html

    http://www.cyberdyne-object-sys.com/oofaq/oo-faq-S-2.1.0.5.html

    http://www.javaworld.com/javaworld/jw-04-2001/jw-0413-polymorph.html

    http://www.ida.his.se/ida/~jonas/ComponentSoftwareCourse/ch6-team2.pdf

Now to be sure, within the context of specific languages and 
environments, I have seen narrower definitions of the term.  But in 
these cases they're defining how Polymorphism works in that particular 
language or environment, where there's no point in discussing the more 
general forms which do not exist.  

I think we actually pretty much agree on how this all works.  It's just 
the definitions of terms where we differ.  Just accept that Polymorphism 
can be done in as static fashion and that it does not necessarily 
involve objects (as my many sources above indicate) and we won't have an 
argument.

>>The latter reference points out that C++ provides genuine Polymorphism without
>>using objects at all:
>>
>>    int IsaT1( T1 a ){ return 1; }
>>    int IsaT1( T2 b ){ return 0; }
>>
>>IsaT1( x );    // returns 0 or 1 depending on arg type
>>
>
>Only it /doesn't/ depend on the arg type.  It depends on the static
>declarations.  That's not the same thing.  
>
The result from "IsaT1( x)" DOES very much "depend on arg type." 
 There's no other way to say it or think of it.  The trick is that the 
language is designed so that the compiler knows at compile time what the 
object type always will be.  Think of it as an optimization, where a 
runtime symbol table lookup is replaced by a direct call to the proper 
function.  

OOP with zero runtime overhead -- this is a FEATURE not a gimmick.

>Try this:
>
>  class A {};
>  class B : public A {};
>  class C : public A {};
>
>  int isaB(A x) {return 0;}
>  int isaB(B x) {return 1;}
>
>  int buggy(A x) {return isaB(x);}
>
>now create a B instance and C instance and try calling isaB() on
>them.  That works OK.  Call buggy() on them.  That fails.
>
It doesn't  "fail".  It merely does not do what YOU want it to do.  

Buggy() by definition only works on objects of type A.  In all calls to 
buggy C++ coerces sub-types of A to type A.  Since x can never be 
anything but type A, the test can never be true.  A global optimizing 
compiler would convert it to "return 0".

Again, this is a feature.

I can see how, if the bulk of your OOP experience was with a late 
binding language like Lisp, then this behavior would seem foreign.  But 
for those of us who's background is primarily with early binding 
languages, it makes sense.

In this case, right or wrong is very much a relative term and depends on 
your background and perspective.

>Feel free to rewrite it with pointers, if you still believe that will
>help.  It won't.  [And you can't even fix that with "virtual"]
>
You are right that virtual does not apply.  However, there is nothing to 
"fix".  Function overloading is a form of Polymorphism that does not 
involve Objects.  Perfectly legitimate per the various 3rd party 
authorities above.

>That's the difference between C++ overloading and proper multiple
>dispatch, as in Lisp.  Overloading is just a syntactic hack [...]
>no different than writing [...]
>different names for each overloaded definition.
>
Partly true (in the case of regular functions) except the user doesn't 
have to make up the goofy names.  This is a significant feature.

However, overloading also applies to operators such as + and *.  In this 
case there is NO WAY to make up different names and get the same effect. 
 It's Polymorphism in it's basic form -- the same method works 
differently when applied to objects of different types.

The operators emphasizes why this aspect of C++ OOP is an extension over 
Python.  In C++ you can define + and * for vectors and also a version 
with scalar arguments.  No way to do that with Python.  Optional 
arguments gives you a small subset of that capability but falls flat for 
some other applications.

OOP doesn't always have to be implemented the way YOU happen to be used 
to.  It doesn't have to be a runtime phenomenon to be legitimate, let 
alone useful.

How is "proper multiple dispatch" any better?

>>In Python you're hosed as there is no way to
>>discriminate class functions by argument signature.  I hope that eventually changes.
>>
>I hope it doesn't.  At least, not unless it changes toward multiple
>dispatch (which is unlikely).
>
Independently of implementation, I am describing a missing feature that 
I think it would be very nice to have.

Python being a late binding language, it probably would do the final 
function selection at runtime just like in LISP.  How would that differ 
from 'multiple dispatch'?  

>Yes.  Just like Python's dict.  [In fact, if you have a quick look at
>the Python source code, you'll find that most of the built-in
>functions are in fact implemented by having pointers at fixed
>locations in the C struct that represents the class, too!]
>
I did not know that.  

Then I would then say Python is using "early binding" for the built-ins. 
 ;o)  

And that it's smart and shows the value of early binding. ;o)

I mean, this case is completely different from C++'s virtual functions, 
right? There's no decision at runtime based on object type, right?  Just 
a static table in partial recognition of the sometimes intolerable cost 
of looking up each name at runtime.  

>It's important that you use the same definitions as
>everybody else, not just make up your own as you're doing here.
>
That might be a fair criticism EXCEPT for the fact that *I* defined my 
terms last week at the start of this branch of the discussion.  If you 
want to go back and argue the original definitions, that's one thing. 
 But you're out of line to accuse ME of being arbitrary when I clearly 
defined the terms up front.

Clearly you're one of those zealots who believes that "late binding" is 
an essential ingredient in Polymorphism and in OOP generally.  I 
disagree and think I've made my point.  "We'll let the viewers decide." 
 In any case I am too exhausted with the subject to continue (unless 
something REALLY juicy comes up).  

However, I would like to hear more about why multiple dispatch is so 
special.

You and I have had civil exchanges in the past.  I hope we can agree to 
disagree in this case without anybody getting their nose bent out of joint.

Regards

--jb

-- 
James J. Besemer		503-280-0838 voice
2727 NE Skidmore St.		503-280-0375 fax
Portland, Oregon 97211-6557	mailto:jb at cascade-sys.com
				http://cascade-sys.com	


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20020826/8e2c231e/attachment.html>


More information about the Python-list mailing list