On 24/03/2016 18:10, Steven D'Aprano wrote:
On Fri, 25 Mar 2016 12:01 am, BartC wrote:

Python 3 (on Windows) might take 200ns. Clisp is 1300ns (interpreted,
presumably). Ruby 170ns. Lua 80ns. Mine 10-20ns. Unoptimised C is 4ns,
but this is not executing code indirectly as most of the rest have to.

"Might"? Are you making those numbers up?

No.

[Timings include loop overheads that need to be factored out.]

Then those numbers are pointless.

Yes, they would need some adjustment to do this stuff properly. FWIW the loop overheads were about 30% in Python, 40% in Ruby, and 20% in mine.

The Python figure, for example, might be
199ns for the loop overhead and 1ns for the function call, or 1ns for the
loop overhead and 199ns for the function call. Or anything in between. How
do you know which is which?

It sounds like they would both need some work!

So there might be room for improvement, but those faster languages are
also simpler.

In the case of C, the line is limited to working with some specific type
(say, an int32). Even there, if the addition might overflow, the behaviour
is undefined and the compiler can do anything it wants (including time
travel,

I'm pretty sure it can't do time travel...

 or erasing your hard disk).

In the case of Python, the line will work with a potentially infinite number
of types: int, float, complex, Fraction, Decimal, subclasses of all the
above, custom numeric types, and anything else that quacks like a number.

Yes, it has to do some dynamic type dispatch. All the languages except C were dynamic (C cheats in so many ways).

However, my bit of code (a for-loop calling an empty function) doesn't on the surface, do anything that requires type dispatch, or does it?

This is where we come to the first differences between how Python works and how, say, my language works (I don't know about Lua, Ruby and Lisp.)

Python bytecode for empty function bill():

 4           0 LOAD_CONST               0 (None)
             3 RETURN_VALUE

Inner loop calling bill():

        >>   13 FOR_ITER                13 (to 29)
             16 STORE_FAST               0 (n)

  8          19 LOAD_GLOBAL              1 (bill)
             22 CALL_FUNCTION            0 (0 positional... )
             25 POP_TOP
             26 JUMP_ABSOLUTE           13


My bytecode for function bill():

0: 000   --------- return

My inner loop bytecode:

1: 005  %4:
1: 006   --------- call                         [&t.bill], 0
1: 006   --------- to_f                         %4, [t.start.av$1:-1]


Half the explanation is right here: I use 1 op in the function, and 2 in the loop. Python uses 2 in the function, and 6 in the loop.

(I use a dedicated repeat-N-times loop that needs no explicit loop variable, only an internal integer count. I use a special 'proc' form of function with no return value. And I use static functions so the byte-code knows the function being called, and knows it returns no value that needs to be popped.)

--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to