Typing system vs. Java

Markus Schaber markus at schabi.de
Fri Aug 10 13:45:27 EDT 2001


Hi,

Alex Martelli <aleaxit at yahoo.com> schrub:
> Far more useful than (Java/Eiffel/&c) type declaration (which still
> need dynamic dispatching of methods) is supposed to be runtime caching
> of the dispatching (I believe that's what Self uses, for example). 

Well - some implementations create an array of member offsets for every 
different implementation of a type (Class or Interface). Then an Object 
gets just a list of arrays.

Now, when you assign an object to a variable of type t, the compler 
just gets a pointer to the interface array from the object (which 
usually is O(1) without multiple inheritance). When you always keep the 
interface array pointer together with the object pointer, you only have 
to do this lookup at explicit casts - at the cost of doubling the size 
of object references.

And every function and attribute access means one pointer indirection, 
as the offsets of the members in the array are fixed - the types are 
statically known.

This means if you want to access a objects member: Look into the offset 
table, position X (which is known at compile time), and add this value 
to the object address - et voilá, this is the members address.

Some good old cisc machines can do such calculations in one assembly 
instruction, and every reasonable cisc processor should do this in less 
than 6 instructions.

Python (as any other language without static types) has to do some (one 
per namespace) complex dictionary lookups including hash calculations 
and string comparisons here, which is _much_ slower than with fixed 
types. 

This applies with interpreted languages as much as with byte-code- or 
machine-code languages.

Even with caching, dynamic lookups will never be as fast as static 
lookups. And with caching, you get in trouble when multi-threading: 
Imagine a method that signals another thread, and this thread replaces 
the method. But your own thread has cached the old method...

> Python can be fast enough for most tasks today (and more every day,
> as machines get faster).  It could be fast enough (without extensions)
> for a few more tasks (perhaps) if very substantial resources were
> expended in adapting advanced optimization technologies (I don't
> think projects to that end in the past, such as Vyper, went anyplace,
> but that could change in the future -- if enough people thought it
> matters, strongly enough to be willing to donate time, money and/or
> skills to the purpose).  Perhaps some language changes might make
> optimization slightly easier, although I have my doubts whether such
> slightly easier optimization could be achieved without losing the key
> characteristics of Python's simplicity and power (untrammeled
> signature based polymorphism, for example: if the libraries started
> being full of type-testing to make optimizer-writers' life slightly
> easier, that would strike a huge blow to Python's power AND
> simplicity).

As long as Python doesn't allow self-modyfing code (means a block of 
code is immutable once compiled), it should be no problem (except 
implemenation effort) to replace the byte-code compiler with one that 
provides machine code.

But this isn't the main slowdown - it is the dynamic lookup for every 
access. But when we change this, we wouldn't have python any more.

>> I think that adding features to allow Python powerful enough to
>> remove the
>> need for extensions would be worth a little bit of extra complexity. 
>> I
> 
> I could hardly disagree more deeply, profoundly and totally than in
> fact
> I do.  Nothing will remove the need for extensions, although their use
> may become less frequent.

Fully agree. The only way to get around this is to have _very good_ 
optimizing compilers, and to include every needed machine-specific 
detail as a language feature.

In a project at our university (Ulm, Germany), we implement an OS using 
a java-like language (older researches used an oberon derivate). We 
included machine level things using a "virtual" class called Magic. 
This class doesn't physically exist, the compiler directly generates 
the corresponding machine code. This way, we have direct access to 
memory (Magic.mem8[]), Intel IO-Space port commands (Magic.Out(), 
Magic.In) and - for use in the memory management classes - magic.Cast. 
We even can declare methods that use interrupt stack frame instead of 
normal one.

But there are still some places where we have to use our nice inline 
feature - sometimes for speed reasons (Memcopy, TCP-Checksum etc), and 
the other times because they are very specific and needed only at one 
place (MMU-Programming, TSC-Register access etc). 

If you don't include assembly into the language, you always will have 
to use extensions that don't follow the language's rules.

markus
-- 
Defend democrathy and freedom!



More information about the Python-list mailing list