Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > RE: pre-PEP: Suite-Based Keywords - syntax proposal

Reply
Thread Tools

RE: pre-PEP: Suite-Based Keywords - syntax proposal

 
 
Robert Brewer
Guest
Posts: n/a
 
      04-17-2005
Bengt Richter wrote:
> The '::' unary suite operator should return an ordered dict
> subtype representing the bindings


Why ordered?


Robert Brewer
MIS
Amor Ministries
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
 
Kay Schluehr
Guest
Posts: n/a
 
      04-17-2005

Robert Brewer wrote:
> Bengt Richter wrote:
> > The '::' unary suite operator should return an ordered dict
> > subtype representing the bindings

>
> Why ordered?


Because You can't otherwise guarantee to feed optional argument
parameters in a correct way.

Example:

x = property(*seq) where:
seq = (item[1] for item in ::
def get_x():
return self.__x
def set_x(value):
self.__x = value
del_x = None
doc = "I'm the 'x' property." )

This statement would not work if the result of '::' ( considered as an
"ordered dict" ) would return simply a dict because the order of the
input parameters matters.

Ciao,
Kay

 
Reply With Quote
 
 
 
 
Bengt Richter
Guest
Posts: n/a
 
      04-17-2005
On 16 Apr 2005 23:43:03 -0700, "Kay Schluehr" <(E-Mail Removed)> wrote:

>
>Robert Brewer wrote:
>> Bengt Richter wrote:
>> > The '::' unary suite operator should return an ordered dict
>> > subtype representing the bindings

>>
>> Why ordered?

>
>Because You can't otherwise guarantee to feed optional argument
>parameters in a correct way.
>
>Example:
>
>x = property(*seq) where:
> seq = (item[1] for item in ::
> def get_x():
> return self.__x
> def set_x(value):
> self.__x = value
> del_x = None
> doc = "I'm the 'x' property." )
>
>This statement would not work if the result of '::' ( considered as an
>"ordered dict" ) would return simply a dict because the order of the
>input parameters matters.
>

Exactly. Except the above example is from the day-old-bread items-tuple-returning version of ::
And with an ordered dict subtype there is no need for the generator expression either,
since there is a values method for dicts (which in the subtype would preserve order). E.g.,

x = property(*seq) where:
seq = (::
def get_x():
return self.__x
def set_x(value):
self.__x = value
del_x = None
doc = "I'm the 'x' property." ).values())

Or more directly:

x = property(*(::
def get_x():
return self.__x
def set_x(value):
self.__x = value
del_x = None
doc = "I'm the 'x' property." ).values())

Or eliminating parens by using dedent to end the :: suite:

x = property(*::
def get_x():
return self.__x
def set_x(value):
self.__x = value
del_x = None
doc = "I'm the 'x' property."
.values())

Regards,
Bengt Richter
 
Reply With Quote
 
Kay Schluehr
Guest
Posts: n/a
 
      04-17-2005
> Exactly. Except the above example is from the day-old-bread
items-tuple-returning version of ::
> And with an ordered dict subtype there is no need for the generator

expression either,
> since there is a values method for dicts (which in the subtype would

preserve order). E.g.,
>
> x = property(*seq) where:
> seq = (::
> def get_x():
> return self.__x
> def set_x(value):
> self.__x = value
> del_x = None
> doc = "I'm the 'x' property." ).values())
>
> Or more directly:
>
> x = property(*(::
> def get_x():
> return self.__x
> def set_x(value):
> self.__x = value
> del_x = None
> doc = "I'm the 'x' property." ).values())


Hmmm ... now You eliminate "where" completely in favor for '::'. This
may be reasonable because '::' is stronger and less context dependent.
But on the other hand it may be also reasonable to eliminate '::'
towards a stronger "where"


x = property(**kw) where kw:
doc = "I'm the 'x' property."
def fget(self):
return self.__x


x = property(*args) where args:
def fget(self):
return self.__x
fset = None
fdel = None
doc = "I'm the 'x' property."


Put definitions into a list:

l = list(*args) where args:
def fget(self):
return self.__x
doc = "I'm the 'x' property."


Nest suites:

x = property(*args) where args:
t = tuple(*t) where t:
def fget(self):
return self.__x
fset = None
fdel = None
doc = "I'm the 'x' property."


Evaluate conditions:

if f(*args)==1 where args:
x = 1
y = 2

I think this version is more mainstream syntax ( and without braces and
additional punctuation ) than the unary prefix operator '::' which
drops statements into expressions within expressions.

Regards,
Kay

 
Reply With Quote
 
Bengt Richter
Guest
Posts: n/a
 
      04-18-2005
On 17 Apr 2005 09:27:34 -0700, "Kay Schluehr" <(E-Mail Removed)> wrote:

>> Exactly. Except the above example is from the day-old-bread

>items-tuple-returning version of ::
>> And with an ordered dict subtype there is no need for the generator

>expression either,
>> since there is a values method for dicts (which in the subtype would

>preserve order). E.g.,
>>
>> x = property(*seq) where:
>> seq = (::
>> def get_x():
>> return self.__x
>> def set_x(value):
>> self.__x = value
>> del_x = None
>> doc = "I'm the 'x' property." ).values())
>>
>> Or more directly:
>>
>> x = property(*(::
>> def get_x():
>> return self.__x
>> def set_x(value):
>> self.__x = value
>> del_x = None
>> doc = "I'm the 'x' property." ).values())

>
>Hmmm ... now You eliminate "where" completely in favor for '::'. This
>may be reasonable because '::' is stronger and less context dependent.
>But on the other hand it may be also reasonable to eliminate '::'
>towards a stronger "where"
>
>
>x = property(**kw) where kw:
> doc = "I'm the 'x' property."
> def fget(self):
> return self.__x
>
>
>x = property(*args) where args:
> def fget(self):
> return self.__x
> fset = None
> fdel = None
> doc = "I'm the 'x' property."
>

I like this. But how would you put "where args:" and "where kw:" if you needed both?
also, is it looking back to see the '*' or '**' to do (:=1).values vs. (:=1)
and how about (:=1).keys() or (:=1).items() ? And what if you wanted to pass
(:=1) as a dict object without ** expansion into a keyword dict?

Maybe we need asterisks on both ends. e.g.,

foo(dct, values, *args, **kw):
where **dct:
x=1
where *values:
x=2
where *args:
x=3
where **kw:
x=4

But that still doesn't give you, e.g.,

foo(keys) where:
keys=sorted((::
from interesting.module import *
).keys())

I like clean sugar, but I still want to be able to
get at the general primitives to compose them in ways
that can't be anticipated until a use case comes up.
And then if the primitives are inaccessible, one is
out of luck or doomed to workaround hacking

>
>Put definitions into a list:
>
>l = list(*args) where args:
> def fget(self):
> return self.__x
> doc = "I'm the 'x' property."
>
>
>Nest suites:
>
>x = property(*args) where args:
> t = tuple(*t) where t:
> def fget(self):
> return self.__x
> fset = None
> fdel = None
> doc = "I'm the 'x' property."
>
>
>Evaluate conditions:
>
>if f(*args)==1 where args:
> x = 1
> y = 2
>
>I think this version is more mainstream syntax ( and without braces and
>additional punctuation ) than the unary prefix operator '::' which
>drops statements into expressions within expressions.
>

I like this mainstream syntax for ordinary use cases, but as mentioned,
I'd still like to have primitives accessible. I don't see why both
couldn't live in harmony

Regards,
Bengt Richter
 
Reply With Quote
 
Steven Bethard
Guest
Posts: n/a
 
      04-18-2005
Kay Schluehr wrote:
> Hmmm ... now You eliminate "where" completely in favor for '::'. This
> may be reasonable because '::' is stronger and less context dependent.
> But on the other hand it may be also reasonable to eliminate '::'
> towards a stronger "where"
>
> x = property(**kw) where kw:
> doc = "I'm the 'x' property."
> def fget(self):
> return self.__x
>
>
> x = property(*args) where args:
> def fget(self):
> return self.__x
> fset = None
> fdel = None
> doc = "I'm the 'x' property."

[snip]
> I think this version is more mainstream syntax ( and without braces and
> additional punctuation ) than the unary prefix operator '::' which
> drops statements into expressions within expressions.


So the object of a "where" is then always an ordered dict? If so, then
I guess I like this proposal best so far.

However, it does seem to have the problem that you can't have any
additional local variables so, for example, list comprehensions are
probably not usable...

Or can you still drop the argument to "where" and just use the names
directly? E.g.:

x = property(fget=fget, doc=doc) where:
doc = "I'm the 'x' property."
def fget(self):
return self.__x

STeVe
 
Reply With Quote
 
Kay Schluehr
Guest
Posts: n/a
 
      04-18-2005
Bengt Richter wrote:
> On 17 Apr 2005 09:27:34 -0700, "Kay Schluehr" <(E-Mail Removed)>

wrote:
>
> >> Exactly. Except the above example is from the day-old-bread

> >items-tuple-returning version of ::
> >> And with an ordered dict subtype there is no need for the

generator
> >expression either,
> >> since there is a values method for dicts (which in the subtype

would
> >preserve order). E.g.,
> >>
> >> x = property(*seq) where:
> >> seq = (::
> >> def get_x():
> >> return self.__x
> >> def set_x(value):
> >> self.__x = value
> >> del_x = None
> >> doc = "I'm the 'x' property." ).values())
> >>
> >> Or more directly:
> >>
> >> x = property(*(::
> >> def get_x():
> >> return self.__x
> >> def set_x(value):
> >> self.__x = value
> >> del_x = None
> >> doc = "I'm the 'x' property." ).values())

> >
> >Hmmm ... now You eliminate "where" completely in favor for '::'.

This
> >may be reasonable because '::' is stronger and less context

dependent.
> >But on the other hand it may be also reasonable to eliminate '::'
> >towards a stronger "where"
> >
> >
> >x = property(**kw) where kw:
> > doc = "I'm the 'x' property."
> > def fget(self):
> > return self.__x
> >
> >
> >x = property(*args) where args:
> > def fget(self):
> > return self.__x
> > fset = None
> > fdel = None
> > doc = "I'm the 'x' property."
> >

> I like this. But how would you put "where args:" and "where kw:" if

you needed both?
> also, is it looking back to see the '*' or '**' to do (:=1).values

vs. (:=1)
> and how about (:=1).keys() or (:=1).items() ? And what if you

wanted to pass
> (:=1) as a dict object without ** expansion into a keyword dict?
>
> Maybe we need asterisks on both ends. e.g.,
>
> foo(dct, values, *args, **kw):
> where **dct:
> x=1
> where *values:
> x=2
> where *args:
> x=3
> where **kw:
> x=4


Yes... Why not?

>
> But that still doesn't give you, e.g.,
>
> foo(keys) where:
> keys=sorted((::
> from interesting.module import *
> ).keys())


This particular statement won't work anyway inside a where-clause
because
"from *" must be called from module level. You would have to import
interesting.module before:

import interesting.module
foo(keys) where:
keys = sorted(interesting.module.__dict__).keys()

But it wasn't ever intended to put arbitrary statements in a kw-suite,
right?

> I like clean sugar, but I still want to be able to
> get at the general primitives to compose them in ways
> that can't be anticipated until a use case comes up.
> And then if the primitives are inaccessible, one is
> out of luck or doomed to workaround hacking


You can always consider "where" as function of a statement. The only
restriction You have to make is to bind "where" to a function-call i.e.
regard each function as a function object with a where() method.


f(*args,**kw ).where( <specifier>,
(<assignment-statement>|
<function-definition>|
<class-definition>)*
)

But that is not a loss of generality because a free (:: x=1 ) can be
mapped onto

dict(**kw).where(**kw, x=1)

and that is

dict(**kw) where **kw:
x=1

I don't see any case where this translation fails. Only if it comes to
functional composition like

f(g(...(h(:: x=1)...))

it may be awkward to expand this into a nested where clauses. You might
probably define the argument not in a suite

Regards,
Kay

 
Reply With Quote
 
Kay Schluehr
Guest
Posts: n/a
 
      04-18-2005
Steven Bethard wrote:

> So the object of a "where" is then always an ordered dict?


Yes.

> If so, then
> I guess I like this proposal best so far.
>
> However, it does seem to have the problem that you can't have any
> additional local variables so, for example, list comprehensions are
> probably not usable...
>
> Or can you still drop the argument to "where" and just use the names
> directly? E.g.:
>
> x = property(fget=fget, doc=doc) where:
> doc = "I'm the 'x' property."
> def fget(self):
> return self.__x


I can't see why this shouldn't work?

The specifiers behind "where" are present to determine the matching
behaviour. The order of a dict is caused by different specifiers i.e. a
dict- or tuple-like specifier. If a specifier is not present only names
can be matched regardless of a sequence and this is always possible
because we still have a dict with names as keys.

What should not be possible are statements like this:

x = property(a, b) where:
doc = "I'm the 'x' property."
def fget(self):
return self.__x

because there is no rule to match doc and fget onto a and b. In this
case we would need specifiers:

x = property(a, b)
where **a:
doc = "I'm the 'x' property."
where **b:
def fget(self):
return self.__x

Ciao,
Kay

 
Reply With Quote
 
Bengt Richter
Guest
Posts: n/a
 
      04-19-2005
On 17 Apr 2005 21:48:47 -0700, "Kay Schluehr" <(E-Mail Removed)> wrote:
<snip>
>> >

>> I like this. But how would you put "where args:" and "where kw:" if

>you needed both?
>> also, is it looking back to see the '*' or '**' to do (:=1).values

>vs. (:=1)
>> and how about (:=1).keys() or (:=1).items() ? And what if you

>wanted to pass
>> (:=1) as a dict object without ** expansion into a keyword dict?
>>
>> Maybe we need asterisks on both ends. e.g.,
>>
>> foo(dct, values, *args, **kw):
>> where **dct:
>> x=1
>> where *values:
>> x=2
>> where *args:
>> x=3
>> where **kw:
>> x=4

>
>Yes... Why not?


On second thought, "where **x:" might as well be "where x:" since ** is a good default,
but I think "where x:" looks too much like and ordinary suite will follow, rather than
capturing the bindings created by the suite and binding that dict to x temporarily.
I would rather see "where x::" to indicate that, which also ties in consistently with
my syntax for for thunks as suite expressions, in that that now gives named def-like
statement versions to all the anonymous versions, when you include this <name>::<suite>
along with <name>(<thunkarglist>):<thunksuite> and <name> def(<defarglist>):<anonymous_def_suite>

Of course that last is equivalent to an ordinary def, and I can't see using it, since a def will
do everywhere except immediately following where, and the assignment form is clearer there, e.g.:

foo(123) where foo=def(x):
print x

as a way to define a transient function and call it


so with that in mind, and I just realized we can do away with * specifiers
if we move that job to where the dict of bindings is used:

foo(dct, values.values(), *args.values(), **kw): #XXX ':' used as function call trailer not good
where dct:: # get suite as dict in all cases
x=1
where values::
x=2
where args::
x=3
where kw::
x=4

Now using the same syntax to define temporarily named thunks for the arg list:

thunk_accepter(tk1, tk2, [1,2], **kw) where: # now where: can introduce an ordinary where suite
tk1(i):
print i
tk2(j):
rejectlist.append(j)
kw::
x = 1
y = 2

This would be equivalent to

thunk_accepter(tk1, tk2, [1,2], **kw) where:
tk1 = (i):
print i
tk2 = (j):
rejectlist.append(j)
kw = ::
x = 1
y = 2

Which might look more "mainstream", and be ok for multiple values, but for a single thunk,
which is probably the most frequent use case, a statement should be able to
end in "where <single assignment or name binder>:" e.g.,

foo(x) where x=1 # minimal silly

or named thunk definition syntax, which binds the name and uses a suite, e.g.,

safe_open(tk, filepath, filemode) where tk(f):
for line in f:
print line[:40]

would be nice and concise. And it looks pretty mainstream, in that
tk(f) looks just like the thunk call that safe_open will do to run the suite
in the local namespace. Might even look good to Brian?

But note that "where tk(f):<suite>" is really equivalent to the assignment form
"where tk = (f):<suite>" much like def foo(): return 'hi' is equivalent to foo = lambda: 'hi'
(and my thunk definition syntax derives from def foo(<arglist>):<suite> minus "def foo"

>
>>
>> But that still doesn't give you, e.g.,
>>
>> foo(keys) where:
>> keys=sorted((::
>> from interesting.module import *
>> ).keys())

>
>This particular statement won't work anyway inside a where-clause
>because
>"from *" must be called from module level. You would have to import
>interesting.module before:
>
> import interesting.module
> foo(keys) where:
> keys = sorted(interesting.module.__dict__).keys()
>
>But it wasn't ever intended to put arbitrary statements in a kw-suite,
>right?

Sure, as arbitrary as inside a function. Import * was a bad example. I never use that,
so I shouldn't have used it in an example, even though on my system it does it, grudgingly:

>>> def foo():

... from math import *
... return vars().keys()
...
<stdin>:1: SyntaxWarning: import * only allowed at module level
>>> foo()

['pow', 'cosh', 'ldexp', 'hypot', 'tan', 'asin', 'log', 'fabs', 'floor', 'sqrt', 'frexp', 'degre
es', 'pi', 'log10', 'sin', 'modf', 'atan', 'ceil', 'sinh', 'cos', 'e', 'tanh', 'radians', 'atan2
', 'fmod', 'exp', 'acos']
>>>


I should have put a safe import inside, using your example
foo(keys) where:
import interesting.module
keys = sorted(interesting.module.__dict__).keys()

If you import it outside of that scope, you will have 'interesting' bound outside.

I'm not saying go wild and do weird things, I'm just saying don't impose arbitrary
restrictions on adults. These explorations are just to illustrate possibilities,
not to advocate them all as good conventional use.

>
>> I like clean sugar, but I still want to be able to
>> get at the general primitives to compose them in ways
>> that can't be anticipated until a use case comes up.
>> And then if the primitives are inaccessible, one is
>> out of luck or doomed to workaround hacking

>
>You can always consider "where" as function of a statement. The only
>restriction You have to make is to bind "where" to a function-call i.e.
>regard each function as a function object with a where() method.


Um, I think that's too narrow for where. Consider

foo = f1; bar=f2; x=k1; y=k2
foo(x)*bar(y)[3].attr

now should

foo(x)*bar(y)[3].attr where:
foo = f1; bar=f2; x=k1; y=k2

act any different? How do you spell this as a where bound to a function call?

>
>
>f(*args,**kw ).where( <specifier>,
> (<assignment-statement>|
> <function-definition>|
> <class-definition>)*
> )
>
>But that is not a loss of generality because a free (:: x=1 ) can be
>mapped onto
>
> dict(**kw).where(**kw, x=1)
>
>and that is
>
> dict(**kw) where **kw:
> x=1



so for
foo(*args) where:
args = dict(**kw).keys() where **kw:
x=1

but it's much easier (now with explorations and ideas above to write

foo(*args.values()) where args::
x=1

>
>I don't see any case where this translation fails. Only if it comes to
>functional composition like
>
> f(g(...(h(:: x=1)...))
>
>it may be awkward to expand this into a nested where clauses. You might
>probably define the argument not in a suite


There are probably some things that won't look reasonable no matter what

But to summarize, I think we should try to write a real grammar for all this,
and show how it would fit in with the real python grammar.

I think I should make a separate post for this
see
grammar for where/letting/with and suite expressions (thunks etc)


Regards,
Bengt Richter
 
Reply With Quote
 
Kay Schluehr
Guest
Posts: n/a
 
      04-19-2005

Bengt Richter wrote:

[...]

> Um, I think that's too narrow for where. Consider
>
> foo = f1; bar=f2; x=k1; y=k2
> foo(x)*bar(y)[3].attr
>
> now should
>
> foo(x)*bar(y)[3].attr where:
> foo = f1; bar=f2; x=k1; y=k2


I think we are diverging again. You are right with Your objection about
my claim of generality but I'm completely against the latter statement
not only because

foo(x) where:
foo = f1

is not much better than

foo(x) where:
def foo():
# do some stuff

which should clearly raise an exception and be abandoned.

After all I start backtracking: the purpose of defining suites is still
prevention of namespaces pollution with helper-functions not a sake of
it's own and not inventing of a suite-based programming style for
everything. The examples You presented have become almost pathological
examples of what should be prevented and where syntax cannot be rigid
enough.

So there are following requierements about we seem to agree:

- define suites on a functions-call scope in order to define helper
functions
that would otherwise pollute external namespaces

- mark the func-call-scope by some keyword either "with" or "where"
because
it has to be separated from the calling environment both for
consistency
and user friendlyness

- Simple matching rules for both keyword-parameters and
argument-tuples.
Make explicit which kind of inference rule is selected.

I think that my last proposal I finally distilled from our discussion
would pretty much fullfill all three requirements whereas that of
Andrey Tatarinov would be somewhat more restrictive and fullfills only
the first two.

Ciao,
Kay

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Python dot-equals (syntax proposal) Jabapyth Python 40 05-03-2010 05:15 PM
Nullable/Notnull : syntax proposal sarnold@free.fr C Programming 21 11-07-2007 05:19 AM
multiple return values (new syntax proposal) aleksandar.ristovski@gmail.com C++ 8 09-10-2006 01:05 AM
IL Generator syntax proposal John Lam Ruby 8 12-07-2005 12:56 AM
PEP-318, billion-and-first syntax proposal Tim Hochberg Python 0 08-10-2004 07:38 PM



Advertisments