syntax for preset locals without using dummy args with defaults

Beni Cherniavsky cben at techunix.technion.ac.il
Thu Jan 16 13:37:50 CET 2003


On 2003-01-15, Bengt Richter wrote:

> On Wed, 15 Jan 2003 10:00:56 +0200 (IST), Beni Cherniavsky <cben at techunix.technion.ac.il> wrote:
>
> >On 2003-01-14, Andrew McGregor wrote:
> >
> >> How about:
> >>
> >> with:
> >>   z = some_expression
> >>   z1 = some_other_expression
> >>   # for consistency, should allow this too.
> >>   def quux(bar):
> >>     do_something()
> >> do:
> >>   def foo(x, y=default):
> >>     do_stuff()
> >>
> >Yes, this is probably optimal (or very close) if we want it at all.
> >
> I have a couple of reservations: 1) I think already the distinction between
> what I have been calling "def-time" and "call-time" is often missed (i.e.,
> def ... defines executable code that builds the executable function whose
> code later gets executed when it is called, and thus there are two distinct
> execution times and codes involved), and the above doesn't make it plain
> unless you already know.
>
> The keywords "with" and "do" in the above don't strongly suggest what is
> supposed to happen IMO, especially since "with" carries a Pascal meaning.
>
I did't refer to the specific keyword names.  with/do are too common to be
reserved for this purpose and don't convey the meaning to an uninitiated
reader.  Now that I think of it, the whole construct is too subtle to be
understood correctly by somebody unfamiliar with it.

> Also, what is the scope and environment of the "do"? I.e., what would
> other statements in the do: suite mean if they appeared before or after
> the def?
>
The same as the def: executed in a nested scope, inside of the scope
established by the do.

> It is crucial to the semantics that it be understood that the expressions in
> the suite of the "with" are only executed once, yet the bindings are copied
> each time the function is called, to preset the local bindings afresh.
> IOW, the effect is something[1] like:
>
If they are copied every time, what do you you gain over just initialising
every time the function is run?  That you don't compute the expressions
again.  But assuming you don't do nasty vars() manipulation, you can't
rebind the bindings of the outer scope - so you don't need to copy again
every time.

>   def _presets():
>       z = some_expression
>       z1 = some_other_expression
>     # for consistency, should allow this too.
>       def quux(bar):
>           do_something()
>       return vars() # capture and return the bindings of interst
>   _presets = _presets() # (the function gets one-time use)
>
>   def foo(x, y=default):
>        vars().update(_presets) # hidden part of locals setup
>        do_stuff()
>
The semantics should be precisely:

def _presets_wrapper():
    z = some_expression
    z1 = some_other_expression
    def quux(bar):
        do_something()

    def foo(x, y=default):
        do_stuff(x, y, z, z1)
    return foo

foo = _presets_wrapper()

> But the functionality is close enough to suggest passing a dict somehow
> to def as an initializer. And the _presets() trick above suggests an
> alternate spelling for a dictionary literal, which might by default imply
> an underlying implementation like a function local namespace (imagining
> a fast implementation where its representation couldbe memcopied like
> a C struct for purposes of initializing function locals before parameter
> bindings are superimposed). Such a dictionary literal might be written like:
>
>   _presets = {:
>       z = some_expression
>       z1 = some_other_expression
>       # for consistency, should allow this too.
>       def quux(bar):
>           do_something()
>
> (where there is no closing ':}' but instead '{:' introduces a suite, and the
> dict value consists in the bindings created therein).
>
You open the can of worms of suites inside an expression.  If you don't
insist on that, you already have such a syntax for dictionary creation:

class _presets:
    z = some_expression
    z1 = some_other_expression
    def quux(bar):
        do_something()
_presets = _presets.__dict__

You can probably automate the last line to with a metaclass.

> Then if you could pass a dict as an initializer to def, you could write, e.g.,
>
>   def(_presets) foo(x, y=default):
>        do_stuff()
>
> Sort of like passing base classes, but a bit different ;-)
>
>
> BTW, the other thing the above doesn't address is persistence of bindings
> (analogous to C static variables containing pointers the still point
> as before on the next call).
>
Well, if you don't copy again you have a simple closure.  But updating is
dirty...  And static variables in C are almost always better expressed as
classes (or structs).

> If there were something analogous to base classes and __metaclass__ for
> functions, it might be interesting...
>
I.e. a way to take a suite and hand it as a code object to some
function/object?  You are about to start a new macros thread :-)

-- 
Beni Cherniavsky <cben at tx.technion.ac.il>

There is an Excel spreadsheet here.  Do you want to open it? y
There was a grid bug in the spreadsheet.  The grid bug bites.





More information about the Python-list mailing list