[Types-sig] Type Inference II

Tim Peters tim_one@email.msn.com
Sun, 19 Dec 1999 18:47:02 -0500


[John Skaller]
> ...
> Another case which inhibits optimisation is loop variables.
> In the loop:
>
> 	for x in y: ....
>
> is it allowed to assign to x?

Yes (explicitly allowed by section 7.3 of the Lang Ref).

> What about mutating y?

Yes but delicate (see 7.3 again); e.g., I have a great deal of code that
does breadth-first traversals via:

    sawit = {root: 1}  # set of things seen so far
    sequence = [root]
    for thing in sequence:
        for child in thing.children():
            if not sawit.has_key(child):
                sawit[child] = 1
                sequence.append(child)
    return sequence   # a breadth-first list of everything reachable

> What about mutating x?

Sure; this one's so obvious it doesn't need to be said <0.9 wink>.

> [Also, an aside: the code
>
> 	for x[1] in y: ...
> 	for x.attr in y: ...
>
> is allowed but I can't see a real use for it.
> Is there one?

I used this once, many years ago, but felt silly doing it.  There was no
real need for it.  Can't recall ever seeing it in other folks' code, either.
Wouldn't miss it.

> Could we simplify the syntax, and required the loop control to
> be a whole variable, or tuple of whole variables (recurively),
> so that the names involved are always bound directly?

OK by me, but do note it would make CPython's grammar more complicated (in
the sense that Grammar/Grammar would grow larger); the current

for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]

shares "exprlist" with the "del" stmt.

> ...
> Tightening up for loops will break code that does things like:
>
> 	(1) do extra increments on an loop variable to skip cases

Nope.  Assigning to the loop variable has no effect on the values assigned
*to* it by the for stmt:

>>> for i in range(5):
        print i
        i = i ** 10
        print i

0
0
1
1
2
1024
3
59049
4
1048576
>>>

> 	(2) mutate a list while scanning it

Again this shouldn't break anything.  "The rules" are already set up to
reflect a simple one-at-a-time implementation.  When you talk about
"caching" the list, though, I don't know what that could mean other than
making a *copy* of it -- but that would be a pessimization, not a speedup.

In any case, loop overhead is usually minor.  It's usually the guts of the
loop that consume the time.

> ...
> 	_f = f # protect our f
> 	from MODULE import * # might destroy f
> 	f = _f # set f back
> 	del _f   # get rid of temporary _f
>
> This is ugly. It also makes inference harder, because
> there is now a control flow issue.
>
> One idea I had was this:
>
> 	import X as Y   # import X, but name it Y in this module
> 	from M import x as v

Has been suggested many times on c.l.py.  To the best of my knowledge, Guido
has never responded to one of these.  But in any case I'd say that a "real
inferencer" that can't deal with a branch-free basic block isn't real enough
for the Types-SIG to worry about -- "import as" belongs in a different
forum.  "import *" is a legit Types-SIG headache, though; Guido already
voted "if they do that, tough nuts to them".

> ...
> I note python currently supports privacy by name mangling,
> but really, this is a hack: for Python 2, a more sophisticated
> architecture would be better.

It had a more sophisticated one, years ago (the now-defunct "access" stmt);
experience with that was bad, so it was tossed and __ was added; Guido isn't
likely to backtrack here.

it's-a-*cute*-hack<wink>-that-works-well-in-practice-ly y'rs  - tim