[Python-Dev] statically nested scopes

Jeremy Hylton jeremy@alum.mit.edu
Thu, 2 Nov 2000 11:11:30 -0500 (EST)

>>>>> "TP" == Tim Peters <tim_one@email.msn.com> writes:

  TP> [Jeremy Hylton]
  >> ...  Guido once explained that his original reservation about
  >> nested scopes was a reaction to their overuse in Pascal.  In
  >> large Pascal programs he was familiar with, block structure was
  >> overused as an organizing principle for the program, leading to
  >> hard-to-read code.

  TP> Note that this problem will be much worse in Python: in Pascal,
  TP> you could always "look up" for the closest-containing func/proc
  TP> that explicitly declares a referenced vrbl.  In Python, you have
  TP> to indirectly *deduce* which vrbls are local to a def, by
  TP> searching the entire body for an appearance as a binding target.
  TP> So you have to "look up" and "look down" from the reference
  TP> point, and it's easy to miss a binding target.

I agree that visual inspection is a tad harder, but I contend that
existing programs that use the same name for a global variable and a
local variable -- and intend for the global to be visible within a
function nested in the local variable's region -- are confusing.  
It's too hard for a first-time reader of the code to figure out what
is going on.

Incidentally, I have yet to see an example of this problem occurring
in anyone's code.  All the examples seem a bit contrived.  I wonder if
anyone has an example in existing code.

  [My SICP example omitted]

  TP> Unfortunately for proponents, this is exactly the kind of SICP
  TP> example that is much better done via a class.

Indeed, the PEP says exactly that: This kind of program is better
done via a class.  My intent was not to show a compelling use of
mutable state.  Instead it was to show that with read-only access,
people could still modify values on enclosing scopes.  The issue is
whether the language allows the programmer to express this intent
clearly or if she has to jump through some hoops to accomplish it.

  TP>                                                Not only is the
  TP> closure version strained by comparison, but as is usual it
  TP> manages to create a bank account with a write-only balance <0.9
  TP> wink>.

  TP>     def deposit(amount):
  TP>         global bank_account.balance balance += amount

  TP> is one old suggested way to explicitly declare non-local names
  TP> and the enclosing block to which they are local (and in analogy
  TP> with current "global", mandatory if you want to rebind the
  TP> non-local name, optional if you only want to reference it).
  TP> There are subtleties here, but explicit is better than implicit,
  TP> and the subtleties are only subtler if you refuse (like Scheme)
  TP> to make the intent explicit.

I'm still not sure I like it, because it mixes local variables of a
function with attribute access on objects.  I'll add it to the
discussion in the PEP (if Barry approves the PEP <wink>), though.

Do you have any opinion on the subtleties?  The two that immediately
come to mind are: 1) whether the function's local are available as
attributes anywhere or only in nested scopes and 2) whether you can
create new local variable using this notation.