At 12:28 PM 4/21/04 -0400, Jewett, Jim J wrote:
from __future__ import noshadow <==> If a name (or its immediately enclosing class) is explicitly declared dynamic, semantics are the same as today.
How do you declare that something is dynamic?
For all other names, the compiler may assume that the nearest enclosing binding of this name will always be in the same namespace. (Names need not all be in a single namespace, but once a particular name is found, that namespace will always be the correct place to look for that name.) Results are undefined if the name is later unbound in that namespace or shadowed by a nearer enclosing namespace.
This actually isn't that different from my proposal for builtins, except that my proposal doesn't have "undefined results". Instead, names that are determined to be builtin are not allowed to be bound via __setattr__, and are never looked up in the globals dictionary.
Question: Should the compiler be able to assume the same *object* (=can bind as local), or only the same namespace (=can do with a single indirection, perhaps sped up with a variant of DLict).
Question: Is there any reason that this should apply only to builtins, rather than to any namespace?
Simplicity. Functions today do only three kinds of lookups: LOAD_CELL(?), LOAD_FAST and LOAD_GLOBAL. LOAD_CELL is an indirect load from a known, specific nested scope. LOAD_FAST loads from an array offset into the current frame object. LOAD_GLOBAL checks globals and then builtins. Module-level and class body code use LOAD_NAME, which looks in locals, globals, and builtins.
Module and class body code is almost never important for application performance, certainly not enough to justify effort on optimization, I think.
So that leaves LOAD_GLOBAL, which I suggest leaving alone in favor of adding LOAD_BUILTIN and/or CALL_BUILTIN. In other words, at that point all lookups made by functions *would* be explicit as to scope, since LOAD_GLOBAL could only fail its first lookup if the global in question was a not-yet-shadowed-but-expected-to-be builtin.
Objection: Users can do something undefined and get "normal" results instead of a warning -- on their own platform. They can even do this strictly through changes to other modules which do not themselves import noshadow. How serious is this objection?
I think my proposal adequate deals with this by disallowing shadowing at runtime. And, if it was desired to disallow shadowing by modifiying globals(), then perhaps globals() and module.__dict__ could simply return a dictionary proxy that prevented modification of the disallowed values. (But the bare dictionary would still be used by the eval loop.)
If a warning is required, will the bookkeeping be needed even in release mode, or will it be an option depending on compiler settings?
The runtime checking in my proposal only requires a bit of work at module setup, and checking when a module attribute is set. Neither of these occur frequently enough in general to be concerned about.