Statement local namespaces summary (was Re: python3: 'where' keyword)

Nick Coghlan ncoghlan at iinet.net.au
Fri Jan 14 08:15:02 CET 2005


Bengt Richter wrote:
> Problems? (Besides NIH, which I struggle with regularly, and had to overcome to accept Tim's
> starting point in this ;-)

The ideas regarding creating blocks whose name bindings affect a different scope 
are certainly interesting (and relevant to the 'using' out-of-order execution 
syntax as well).

Out-of-order execution appeals to me, but the ability to flag 'hey, this is just 
setup for something I'm doing later' might be a reasonable alternative 
(particularly with the affected names highlighted on the first line). As Jeff 
pointed out, it would be significantly less surprising for those encountering 
the construct for the first time. Folding code editors would be able to keep the 
setup clause out of the way if you really wanted to hide it.

On the other hand, it might be feasible to construct a virtually identical 
out-of-order two suite syntax, similar to the mathematical phrasing "let f = 
c/lambda where f is the frequency, c is the speed of light and lambda is the 
wavelength". Either way, you've convinced me that two suites (and a new compound 
statement), as well as specifying which names can be rebound in the containing 
scope, is a better way to go than trying to mess with the definition of Python 
statements.

On keywords, while 'let' is nice for assignments, I find it just doesn't parse 
properly when I put function or class definitions in the clause. So, I'll swap 
it for 'use' in the examples below. The statement could then be read "use these 
outer bindable names, and this additional code, in this suite". YMMV, naturally.

Let's consider some of the examples given for 'where' using an in-order let/in 
type syntax (the examples only bind one name at a time, but would allow multiple 
names):

# Anonymous functions
use res:
   def f(x):
     d = {}
     exec x in d
     return d
in:
   res = [f(i) for i in executable]

# Declaring properties
class C(object):
   use x:
     def get(self):
       print "Demo default"
     def set(self, value):
       print "Demo default set"
   in:
     x = property(get, set)

# Design by contract
use foo:
   def pre():
     pass
   def post():
     pass
in:
   @dbc(pre, post)
   def foo():
     pass

# Singleton classes
use C:
   class _C:
     pass
in:
   C = _C()

# Complex default values
use f:
   def default():
     return "Demo default"
in:
   def f(x=default()):
     pass

They actually read better than I expected. Nicely, the semantics of this form of 
the syntax *can* be articulated cleanly with current Python:

use <names>: <use-suite>
in: <in-suite>

as equivalent to:

def __use_stmt():
   <use-suite>
   def _in_clause():
     <in-suite>
     return <names>
   return _in_clause()
__use_stmt_args = {}
<names> = __use_stmt()
del __use_stmt

Those semantics don't allow your switch statement example, though, since it 
doesn't use any magic to write to the outer scope - it's just a normal return 
and assign.

However, I don't think starting with these semantics would *preclude* adding the 
ability to name the second block at a later date, and make the name rebinding 
part of executing that block - the standard usage doesn't really care *how* the 
names in the outer scope get bound, just so long as they do. Whether I think 
that's a good idea or not is an entirely different question :)

Another aspect to consider is whether augmented assignment operations in the 
inner-scopes should work normally - if so, it would be possible to alter the 
semantics to include passing the existing values as arguments to the inner scopes.

Moving on to considering a two-suite out-of-order syntax, this would have 
identical semantics to the above, but a syntax that might look something like:

as <names>: <in-suite>
using: <use-suite>

# Anonymous functions
as res:
   res = [f(i) for i in executable]
using:
   def f(x):
     d = {}
     exec x in d
     return d

# Declaring properties
class C(object):
   as x:
     x = property(get, set)
   using:
     def get(self):
       print "Demo default"
     def set(self, value):
       print "Demo default set"

# Design by contract
as foo:
   @dbc(pre, post)
   def foo():
     pass
using:
   def pre():
     pass
   def post():
     pass

# Singleton classes
as C:
   C = _C()
using:
   class _C:
     pass

# Complex default values
as f:
   def f(x=default()):
     pass
using:
   def default():
     return "Demo default"

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at email.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.skystorm.net



More information about the Python-list mailing list