Python from Wise Guy's Viewpoint
Adam Warner
usenet at consulting.net.nz
Fri Oct 31 09:29:03 EST 2003
Hi Fergus Henderson,
> Yes, we covered that already. But that's not what is happening in
> the scenario that I was describing. The scenario that I'm describing is
>
> Collection c;
>
> ...
> foreach x in c do
> use(x);
>
> where use(x) might be a method call, a field access, or similar.
> For example, perhaps the collection is a set of integers, and you
> are computing their sum, so use(x) would be "sum += x".
>
> I think that in these situations, dynamically typed language
> implementations will do O(N) dynamic type checks, where N is the number
> of elements in "c". In theory it is possible to optimize these away,
> but I don't know of any such implementations that do, and I would be
> suprised if there are any (except perhaps in limited cases, e.g. when
> the collection is an array or is implemented using an array).
I've implemented a collection of integers as a list:
* (disassemble
(compile nil
(lambda ()
(declare (optimize (safety 0)))
(let ((c '(1 2 3 4 5 6 7 8 9 10)))
(loop for x of-type (integer 1 10) in c
sum x of-type fixnum)))))
; Compiling lambda nil:
; Compiling Top-Level Form:
482C1160: .entry "lambda nil"() ; (function nil fixnum)
78: pop dword ptr [ebp-8]
7B: lea esp, [ebp-32]
7E: xor eax, eax ; No-arg-parsing entry point
80: mov ecx, [#x482C1158] ; '(1 2 3 4 ...)
86: xor edx, edx
88: jmp L1
8A: L0: mov eax, [ecx-3]
8D: mov ecx, [ecx+1]
90: add edx, eax
92: L1: cmp ecx, #x2800000B ; nil
98: jne L0
9A: mov ecx, [ebp-8]
9D: mov eax, [ebp-4]
A0: add ecx, 2
A3: mov esp, ebp
A5: mov ebp, eax
A7: jmp ecx
No type checks. And 32-bit assembly arithmetic (but the type bits are
still present. most-positive-fixnum is 536,870,911).
>>Regarding your earlier question, though, the great trick in Self was
>>to remember the result of a check and thus avoid doing it again
>>whenever possible. If you do "y := x + 1", and you determine that "x"
>>is a floating point number, then you know that "y" will also be a
>>floating point number immediately afterwards.
>
> Sure. That helps an implementation avoid checking the type of the collection
> "c" at every element access. But it doesn't help the implementation avoid
> checking the type of the element "x" at each iteration of the loop.
Lisp provides standard ways to supply declarations. Some implementations
will trust those declarations in order to optimise the code at compile
time.
>>This points to a general observation. Dealing with the #1 style
>>dynamic type errors is a subset of dealing with dynamic dispatch in
>>general. [....] any optimizations that get rid of these dynamic lookups,
>>will also get rid of type checks just by their nature.
>
> That's true. But the difference between dynamically typed languages and
> statically typed languages is that in dynamically typed languages, *every*
> data access (other than just copying data around) involves a dynamic dispatch.
> Sure, implementations can optimize a lot of them away. But generally you're
> still left lots that your implementation can't optimize away, but which
> would not be present in a statically typed language, such as the O(N)
> dynamic type checks in the example above.
Again, Lisp provides standard ways to supply declarations. Some
implementations will trust those declarations in order to optimise the
code at compile time. And use the declarations for type inference.
Followup-To is set as comp.lang.lisp.
Regards,
Adam
More information about the Python-list
mailing list