By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,950 Members | 1,005 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,950 IT Pros & Developers. It's quick & easy.

pre-PEP: Suite-Based Keywords

P: n/a
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1

In general, a suite following a function call creates a new scope. The
bindings created in this scope get passed to the function as keyword
arguments.

Suite-based keyword arguments can be mixed with regular arguments:

f(1, 2, y = 4):
x = 1

Motivation
==========

One motivation for suite-based keywords is to allow cleaner definitions of
properties. Currently, properties are typically define as in this
example:

class C(object):
def getx(self):
return self.__x
def setx(self, value):
self.__x = value
def delx(self):
del self.__x
x = property(getx, setx, delx, "I'm the 'x' property.")

The 'getx', 'setx', and 'delx' methods get defined in the namespace of the
class even though one wants only to pass them to 'property'. Ideally, one
would want these methods to be defined in their own namespace. Also, it
would be helpful when reading the code if the layout of the code gave
visual indication that their only purpose is to be used in a property.

Using suite-based keyword arguments, and without any changes to the
'property' type, this code can be written as:

class C(object):
x = property():
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

Here, 'fget', 'fset' and 'fdel' do not wind up as methods of the class,
and it is visually clear that they are methods only for the 'x' property.
Also, this code is less bug-prone since the name of each method need
appear only once.

Passing callbacks in other situations is made similarly easier and
cleaner:

setHandlers():
def success():
print 'success'
def failure():
print 'an error has occured'
def apocalypse():
print 'a serious error has occured'

a = [1,3,2]
a.sort():
def cmpfunc(x,y):
return cmp(x,y)

Situations that do not require callbacks can also be better organized
using suite-based keywords. For example, here is code as it would
currently be written in Python:

if a:
x = 1
else:
x = 2
f(x=x)

When reading this code, one reaches the 'if' statment without knowing what
its purpose is-- layout of the code does not indicate that the 'if'
statement is calculating an argument to 'f'. Also, it requires a binding
that serves no purpose other than to hold an argument to 'f', yet this
binding persists for the rest of the surrounding function.

Here is the same code using suite-based keyword arguments

f():
if a:
x = 1
else:
x = 2

When reading this code, it is easy to skip over everything that is
involved in calling 'f', if one so desires. Since the suite has its own
namespace, one does not have to worry that the suite creates some bindings
that will be important later in the function.
Jul 19 '05 #1
Share this Question
Share on Google+
31 Replies


P: n/a
Brian Sabbey wrote:
class C(object):
x = property():
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x


After seeing this example, I think I'll go on a killing spree if your
proposal doesn't get used in Python 2.5 or 2.6. Defining properties like
that would be awesome, only better.
Jul 19 '05 #2

P: n/a
I_vote_yes(James):
I_understand_what_it_does = True
Makes_code_formatting_way_more_managable_in_tough_ cases = True
Makes_code_way_more_readable = True
To_cool = True

On Friday 15 April 2005 04:45 pm, Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1

In general, a suite following a function call creates a new scope. The
bindings created in this scope get passed to the function as keyword
arguments.

Suite-based keyword arguments can be mixed with regular arguments:

f(1, 2, y = 4):
x = 1

Motivation
==========

One motivation for suite-based keywords is to allow cleaner definitions of
properties. Currently, properties are typically define as in this
example:

class C(object):
def getx(self):
return self.__x
def setx(self, value):
self.__x = value
def delx(self):
del self.__x
x = property(getx, setx, delx, "I'm the 'x' property.")

The 'getx', 'setx', and 'delx' methods get defined in the namespace of the
class even though one wants only to pass them to 'property'. Ideally, one
would want these methods to be defined in their own namespace. Also, it
would be helpful when reading the code if the layout of the code gave
visual indication that their only purpose is to be used in a property.

Using suite-based keyword arguments, and without any changes to the
'property' type, this code can be written as:

class C(object):
x = property():
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

Here, 'fget', 'fset' and 'fdel' do not wind up as methods of the class,
and it is visually clear that they are methods only for the 'x' property.
Also, this code is less bug-prone since the name of each method need
appear only once.

Passing callbacks in other situations is made similarly easier and
cleaner:

setHandlers():
def success():
print 'success'
def failure():
print 'an error has occured'
def apocalypse():
print 'a serious error has occured'

a = [1,3,2]
a.sort():
def cmpfunc(x,y):
return cmp(x,y)

Situations that do not require callbacks can also be better organized
using suite-based keywords. For example, here is code as it would
currently be written in Python:

if a:
x = 1
else:
x = 2
f(x=x)

When reading this code, one reaches the 'if' statment without knowing what
its purpose is-- layout of the code does not indicate that the 'if'
statement is calculating an argument to 'f'. Also, it requires a binding
that serves no purpose other than to hold an argument to 'f', yet this
binding persists for the rest of the surrounding function.

Here is the same code using suite-based keyword arguments

f():
if a:
x = 1
else:
x = 2

When reading this code, it is easy to skip over everything that is
involved in calling 'f', if one so desires. Since the suite has its own
namespace, one does not have to worry that the suite creates some bindings
that will be important later in the function.


--
James Stroud, Ph.D.
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
Jul 19 '05 #3

P: n/a
Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in
Python. For example, the typical way to define a class property winds up
polluting the class's namespace with the property's get/set methods. By
allowing keyword arguments to be defined in a suite following a function
call, complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1


ISTM the syntax is ambiguous. How do you interpret
if f():
x = 1
?

Is a suite alllowed only when a block could not be introduced in the current syntax?

Kent
Jul 19 '05 #4

P: n/a
On Fri, 15 Apr 2005 19:32:02 -0700, James Stroud <js*****@mbi.ucla.edu> wrote:
I_vote_yes(James):
I_understand_what_it_does = True
Makes_code_formatting_way_more_managable_in_tough_ cases = True
Makes_code_way_more_readable = True
To_cool = True

On Friday 15 April 2005 04:45 pm, Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.
Kind of cool. If we had full lambdas aka as anonymous defs (def foo(...) with foo left out ;-)
would this be concise sugar for the equivalents shown below your examples?

(The rule for parsing the suite of an anonymous def is that the left column of the first non-space
character of the first suite statement following the def(): becomes the suite indent reference,
and a dedent to the left of that ends the def(): or a closing bracket not opened in the def(): suite
also ends it. Otherwise it is standard suite indentation)
Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1
f(**def():
x = 1
return vars())

In general, a suite following a function call creates a new scope. The
bindings created in this scope get passed to the function as keyword
arguments.

Suite-based keyword arguments can be mixed with regular arguments:

f(1, 2, y = 4):
x = 1
f(1, 2, y = 4,
**def():
x =1
return vars())
Motivation
==========

One motivation for suite-based keywords is to allow cleaner definitions of
properties. Currently, properties are typically define as in this
example:

class C(object):
def getx(self):
return self.__x
def setx(self, value):
self.__x = value
def delx(self):
del self.__x
x = property(getx, setx, delx, "I'm the 'x' property.")

The 'getx', 'setx', and 'delx' methods get defined in the namespace of the
class even though one wants only to pass them to 'property'. Ideally, one
would want these methods to be defined in their own namespace. Also, it
would be helpful when reading the code if the layout of the code gave
visual indication that their only purpose is to be used in a property.

Using suite-based keyword arguments, and without any changes to the
'property' type, this code can be written as:

class C(object):
x = property():
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x clas C(object):
x = property(
**def():
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x
return vars())

Here, 'fget', 'fset' and 'fdel' do not wind up as methods of the class,
and it is visually clear that they are methods only for the 'x' property.
Also, this code is less bug-prone since the name of each method need
appear only once.

Passing callbacks in other situations is made similarly easier and
cleaner:

setHandlers():
def success():
print 'success'
def failure():
print 'an error has occured'
def apocalypse():
print 'a serious error has occured' setHandlers(**def():
def success():
print 'success'
def failure():
print 'an error has occured'
def apocalypse():
print 'a serious error has occured'
return vars())
a = [1,3,2]
a.sort():
def cmpfunc(x,y):
return cmp(x,y) a.sort(**def():
def cmpfunc(x,y)
return vars())
Situations that do not require callbacks can also be better organized
using suite-based keywords. For example, here is code as it would
currently be written in Python:

if a:
x = 1
else:
x = 2
f(x=x)

When reading this code, one reaches the 'if' statment without knowing what
its purpose is-- layout of the code does not indicate that the 'if'
statement is calculating an argument to 'f'. Also, it requires a binding
that serves no purpose other than to hold an argument to 'f', yet this
binding persists for the rest of the surrounding function.

Here is the same code using suite-based keyword arguments

f():
if a:
x = 1
else:
x = 2
f(**def():
if a:
x = 1
else:
x = 2
return vars())
When reading this code, it is easy to skip over everything that is
involved in calling 'f', if one so desires. Since the suite has its own
namespace, one does not have to worry that the suite creates some bindings
that will be important later in the function.

Obviously leaving out the "**def(" and the "return vars())" makes it cleaner ;-)

Regards,
Bengt Richter
Jul 19 '05 #5

P: n/a
Kent Johnson wrote:
Brian Sabbey wrote:
Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1

ISTM the syntax is ambiguous. How do you interpret
if f():
x = 1
?

Is a suite alllowed only when a block could not be introduced in the
current syntax?


I like this PEP a lot, but your concern is valid. Maybe Brian could
modify the PEP slightly to disambiguate. How about using an ellipsis in
the argument list to signify suite-based keywords? Examples:

f(...):
x = 1

class C(object):
x = property(...):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

d = dict(...):
a = 1
b = 2

Using an ellipsis in a statement that would begin a different kind of
block is illegal and generates a syntax error. Note that this usage
seems to fit well with the definition of "ellipsis".

http://dictionary.reference.com/search?q=ellipsis

Shane
Jul 19 '05 #6

P: n/a
On Fri, 15 Apr 2005 16:45:55 -0700, Brian Sabbey <sa****@u.washington.edu> wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Sorry, I replied to to you via James Stroud's reply (q.v.) ;-)
BTW, I like this suite-based keword definition for calls better
than the thunk stuff ;-)

Regards,
Bengt Richter
Jul 19 '05 #7

P: n/a
Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1


Pretty cool, but it interferes with current suites.

How would you write

if f(x=1):
print "yes"

using suite-based keyword args?

Reinhold
Jul 19 '05 #8

P: n/a
How would you write

if f(x=1):
print "yes"

using suite-based keyword args?


Good point.
Then we should remove the extra ':' at the end of the function invocation
:

if f(x=@>):
value of x
print "yes"

if f(@**>):
x: value of x
print "yes"
Jul 19 '05 #9

P: n/a
The idea is interesting but not unambigously realizable. Maybe one
should introduce some extra syntax for disambiguation and thereby
generalize the proposal.

as <specifier>:
# list of definitions and assignments

Proposed specifiers are dict, tuple, *, ** and func.
- as dict:

conversion into a dictionary

Example:

d = as dict:
doc = "I'm the 'x' property."
def fget(self):
return self.__x

We would get d = {"doc":"I'm the 'x' property.", "fget":fget}
- as **:

conversion into keyword-arguments. This comes close in spirit to the
original proposal

Example:

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

- as tuple:

conversion into a tuple. Preserving order.

Example:

t = as tuple:
doc = "I'm the 'x' property."
def fget(self):
return self.__x
t[1]

<function fget at 0x00EC4770>
- as *:

conversion into an argument tuple. Preserving order.

Example:

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

- as func(*args,**kw):

Anoymus functions. Replacement for lambda. Support for
arbirtray statements?

Examples:

p = as func(x,y): x+y
p(1,2)

i,j = 3,4
if (as func(x,y): x+y) (i,j) > 10:
print True
Ciao,
Kay

Jul 19 '05 #10

P: n/a
Shane Hathaway wrote:
I like this PEP a lot, but your concern is valid. Maybe Brian could
modify the PEP slightly to disambiguate. How about using an ellipsis in
the argument list to signify suite-based keywords? Examples:

f(...):
x = 1

class C(object):
x = property(...):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

d = dict(...):
a = 1
b = 2

Using an ellipsis in a statement that would begin a different kind of
block is illegal and generates a syntax error. Note that this usage
seems to fit well with the definition of "ellipsis".

http://dictionary.reference.com/search?q=ellipsis

Shane


I like the ellipsis syntax a lot, it greatly helps the proposal IMHO.

Regards,
Nicolas
Jul 19 '05 #11

P: n/a
Shane Hathaway wrote:
Kent Johnson wrote:
Brian Sabbey wrote:
Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1

ISTM the syntax is ambiguous. How do you interpret
if f():
x = 1
?

Is a suite alllowed only when a block could not be introduced in the
current syntax?


I like this PEP a lot, but your concern is valid. Maybe Brian could
modify the PEP slightly to disambiguate. How about using an ellipsis in
the argument list to signify suite-based keywords? Examples:

f(...):
x = 1

class C(object):
x = property(...):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

d = dict(...):
a = 1
b = 2

Using an ellipsis in a statement that would begin a different kind of
block is illegal and generates a syntax error. Note that this usage
seems to fit well with the definition of "ellipsis".

http://dictionary.reference.com/search?q=ellipsis

Shane


Yes, my description of the syntax was ambiguous. To clarify, I intended
the syntax to be backwardly compatible. That is, one would not be able to
use a suite to define keywords if there already exists a suite for other
reasons. So, one would not be able to use a suite to pass keywords to 'f'
in this situation:

if f():
x = 1

This code should behave exactly as it does now.

I agree that the ellipsis idea probably makes the code more readable, and
it may be a good idea to have them for that reason. However, ellipses are
not necessary as a way to disambiguate the syntax; all statements
containing suites currently begin with a keyword, and keyword suites would
not.

-Brian
Jul 19 '05 #12

P: n/a
Reinhold Birkenfeld wrote:
Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1


Pretty cool, but it interferes with current suites.

How would you write

if f(x=1):
print "yes"

using suite-based keyword args?

Reinhold


You wouldn't be able to use suite keywords in that situation. Also, one
would not be able to use suite keywords when there is more than one
function call on the same line:

y = f()*g():
x = 1 # ?? not allowed

There is only so much suites can do. Cases in which you want to do both
are probably far enough between that it seems acceptable to me to require
two suites:

t = f():
x = 1
if t:
y = 1

In general, I think that anything more than just a function call with an
optional assignment should be disallowed:

y = [f()]: # ? probably shouldn't be allowed
x = 1

-Brian
Jul 19 '05 #13

P: n/a
Bengt Richter wrote:
On Fri, 15 Apr 2005 19:32:02 -0700, James Stroud <js*****@mbi.ucla.edu> wrote:
I_vote_yes(James):
I_understand_what_it_does = True
Makes_code_formatting_way_more_managable_in_tough_ cases = True
Makes_code_way_more_readable = True
To_cool = True

On Friday 15 April 2005 04:45 pm, Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.
Kind of cool. If we had full lambdas aka as anonymous defs (def foo(...) with foo left out ;-)
would this be concise sugar for the equivalents shown below your examples?

(The rule for parsing the suite of an anonymous def is that the left column of the first non-space
character of the first suite statement following the def(): becomes the suite indent reference,
and a dedent to the left of that ends the def(): or a closing bracket not opened in the def(): suite
also ends it. Otherwise it is standard suite indentation)
Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1


f(**def():
x = 1
return vars())


Yes, it seems it would just be sugar for full lambdas. Although, in this
example and the others, wouldn't you have to actually call the anonymous
function?

f(**(def():
x = 1
return vars())())

Otherwise it seems like you are trying to pass a function, not the
keywords the function returns.

One could, of course, also do the same with a named function:

def no_longer_anonymous():
x = 1
return vars()

f(**no_longer_anonymous())

-Brian
Jul 19 '05 #14

P: n/a
Nicolas Fleury wrote:
Shane Hathaway wrote:
I like this PEP a lot, but your concern is valid. Maybe Brian could modify the PEP slightly to disambiguate. How about using an ellipsis in the argument list to signify suite-based keywords? Examples:

f(...):
x = 1

class C(object):
x = property(...):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

d = dict(...):
a = 1
b = 2

Using an ellipsis in a statement that would begin a different kind of block is illegal and generates a syntax error. Note that this usage seems to fit well with the definition of "ellipsis".

http://dictionary.reference.com/search?q=ellipsis

Shane


I like the ellipsis syntax a lot, it greatly helps the proposal IMHO.

Regards,
Nicolas


I think the usage of the block is still limited in Shawns answer. Kents
objection can be evaded but Reinhold Birkenfelds remains valid.

The statement

f(...):
x = 1

is still not an expression like f(x=1) is. I think one has to mark
somehow the scope of the suite-based keywords.

In the examples below we can identifiy the expression belonging to f
without ambiguities and restrictions.

f(y=0,..)
.. x = 1

if f(y=2,..) == 1:
.. x = 5
def g(a):
a**2-1
return 8

Note that the colon after f has vanished as expected for a call.

Ciao,
Kay

Jul 19 '05 #15

P: n/a
Shane Hathaway wrote:
I like this PEP a lot, but your concern is valid. Maybe Brian could
modify the PEP slightly to disambiguate. How about using an ellipsis in
the argument list to signify suite-based keywords? Examples:

f(...):
x = 1

class C(object):
x = property(...):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x

d = dict(...):
a = 1
b = 2


I also like the ellipsis idea much better than the original proposal.
While I figured out what the original syntax meant after half a minute
of staring at it (unlike the thunk proposal which I still can't decode),
I couldn't help but feel that I'd like a visual cue that arguments had
been omitted. Seeing
f():
gives me only ':' as a tiny clue that arguments have been omitted. And
':' is used in all Python suites, so it doesn't have a good intuition
associated with it. Using ellipsis or something similar to indicate
that keyword arguments have been omitted would make this much easier for
me to read.

STeVe
Jul 19 '05 #16

P: n/a
On 16 Apr 2005 09:07:09 -0700, "Kay Schluehr" <ka**********@gmx.net> wrote:
The idea is interesting but not unambigously realizable. Maybe one
should introduce some extra syntax for disambiguation and thereby
generalize the proposal. This is intriguing. I am reminded of trailing "where x is something" phrase, but with
an implied x.
as <specifier>:
# list of definitions and assignments ISTM this list, other than for func, always could be considered to
generate an ordered sequence of (key, value) pairs that need to be plugged into
the preceding context. Where to plug it in is implicit, but it could be given
explicit target name(s) in an expression, e.g.,
<expr> where: <where-suite>

and <where-suite> would be a series of assignments like for suite-based keywords, except that
the key names would be used in resolving the names in the expression preceding the where:, e.g.,
foo(x, y) where:
x = 1
y = 2

would make the foo call using the where bindings by name, here effectively calling foo(1, 2)
But sometimes we want all the bindings in a suite in a chunk, as with suite-based keyword bindings.

I'm proposing below a unary suite operator spelled '::' which will return a single tuple of 2-tuples
representing the ordered bindings produced by the statement suite following the '::' Thus ::<suite>
is a general expression that can be used anywhere an expression can be used. (I'll explain indentation rules).

The "::" expression I'm proposing generalizes capturing suite bindings into an ordered sequence of (key,value)
tuples, like an ordered vars().items() limited to the bindings produced in the suite following "::"
Thus
items = ::
x = 1
y = [1,2]
def foo():pass

print items => (('x', 1), ('y', [1, 2]), ('foo', <function foo at 0x02EE8D14>))

Now we can use a :: expression in a where: spec, e.g.

d = dict(items) where:
items = ('added','value') + :: # note that :: is a unary suite operator producing a tuple of tuples
x = 1
y = [1,2]
def foo():pass

where: actually introduces a suite of scoped assignments much like :: e.g.,
d = {key:value} where: key='x'; value='123' # where is ;-greedy on the same line
print d => {'x':123}

or a multi-parameter call
foo(x, y=23, *args, **kw) where:
x = 333; y = 555
args = [44, 55, 66]
kw = dict(::
z = 'zee'
class C(object): pass
c = C()
del C )

resulting in foo being called like foo(333, 555, 44, 55, 66, z='zee', c=C()) # except C was transiently defined
You can also use a :: expression directly, skipping the where: reference resolution mechanism, e.g.,

d = dict(::
x = 1
y = [1,2]
def foo():pass) # closing bracket not opened in :: suite ends the suite like a sufficient dedent would

It can also participate as a normal expression anywhere a tuple of tuples could go, e.g.

print list(t[0] for t in ::
x = 1
y = [1,2]
def foo():pass)
=> ['x', 'y', 'foo']

Now we can rewrite some examples. Thanks for the inspiration to generalize/orthogonalize ;-)

Proposed specifiers are dict, tuple, *, ** and func.
- as dict:

conversion into a dictionary

Example:

d = as dict:
doc = "I'm the 'x' property."
def fget(self):
return self.__x d = dict(items) where:
items = ::
doc = "I'm the 'x' property."
def fget(self):
return self.__x

Or more concisely

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

We would get d = {"doc":"I'm the 'x' property.", "fget":fget}
- as **:

conversion into keyword-arguments. This comes close in spirit to the
original proposal BTW, this would happen to cover dict alternatively by way of your format
d = dict():
as **: key=value #etc
Example:

x = property():
as **:
doc = "I'm the 'x' property."
def fget(self):
return self.__x
x = property(**kw) where:
kw = dict(::
doc = "I'm the 'x' property."
def fget(self):
return self.__x)
or
x = property(fget=fget, doc=doc) where:
doc = "I'm the 'x' property."
def fget(self):
return self.__x
- as tuple:

conversion into a tuple. Preserving order.

Example:

t = as tuple:
doc = "I'm the 'x' property."
def fget(self):
return self.__x
>>> t[1]
<function fget at 0x00EC4770>

"as tuple:" is special sugar for
t = tuple(*v) where:
v = (t[1] for t in ::
doc = "I'm the 'x' property."
def fget(self):
return self.__x )


- as *:

conversion into an argument tuple. Preserving order. That's the same as passing values to tuple above
Example:

x = property():
as *:
def get_x():
return self.__x
def set_x(value):
self.__x = value
del_x = None
doc = "I'm the 'x' property."
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." )

- as func(*args,**kw):

Anoymus functions. Replacement for lambda. Support for
arbirtray statements? I prefer dropping combinations of def and/or <name> from def <name>(<arglist>): <suite>
to get

def <name>(<arglist>): <suite> # normal def
def (<arglist>): <suite> # anonymous def
<name>(<arglist>): <suite> # named callable suite, aka named thunk
(<arglist>): <suite> # anonymous callable suite, aka thunk

any of which can be passed to a decorator or bound or passed to functions etc.

The parsing of indentation for the three last definitions is like for the :: unary suite operator
i.e., they are all expressions, not statements, and ::<suite> is an expression that ends where the
<suite> ends, so there are some rules. The first is that a closing bracket not opened within the suite
ends the suite. This is typically the closing paren of a function call, but could be anything, e.g.,
print [:: x=123; y=456] => [(('x', 123), ('y', 456))] # ie the :: value is a single tuple of tuples.

More typical would be the use of def(<arglist>):<suite> as a substitute for lambda <arglist>:<expr>

BTW, note that :: is ;-greedy in a single-line multi-statement suite, so
items = :: x=1; y=2 # => (('x',1), ('y',2))
I.e., it has the effect of
items = ::
x = 1
y = 2
Not
items == ::
x = 1
y = 2

The same greediness goes for "where:"

Examples:

p = as func(x,y): x+y
p(1,2)
p = def(x, y): x+y
i,j = 3,4
if (as func(x,y): x+y) (i,j) > 10:
print True


if (def(x,y): x+y) (i,j) > 10:
print true

I haven't thought of all the uses for anonymous callable suites (thunks), but imagine as callback:
(putting it as an unusual default parameter makes it bind in the same namspace as the definintion of foo)

def foo(x, cb=(y):print y):
cb(x)

foo(3) # => prints 3 and assigns y=3 as local-to-foo-definer side effect (often main effect)

foo(123, (z):print 'Setting z=%r'%z) => prints Setting z=123 and sets z=123 locally to foo caller.

foo(456, lambda *ignore:None) # also legal, foo doesn't know what callable it's being passed
The suite-based keyword call syntax

foo():
x = 1
y = [1,2]
def foo():pass

can be handled with the more general

foo(**kw) where: kw = dict(::
x = 1
y = [1,2]
def foo():pass)

This is a new rev on my thoughts. Expect contradictions with older stuff.
Naturally I like my newest ideas best ;-)

Regards,
Bengt Richter
Jul 19 '05 #17

P: n/a
On Sat, 16 Apr 2005 14:02:32 -0700, Brian Sabbey <sa****@u.washington.edu> wrote:
Bengt Richter wrote:
On Fri, 15 Apr 2005 19:32:02 -0700, James Stroud <js*****@mbi.ucla.edu> wrote:
Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1
f(**def():
x = 1
return vars())


Yes, it seems it would just be sugar for full lambdas. Although, in this
example and the others, wouldn't you have to actually call the anonymous
function?

D'oh, yes, but you got the idea ;-)
f(**(def():
x = 1
return vars())())

Otherwise it seems like you are trying to pass a function, not the
keywords the function returns.

One could, of course, also do the same with a named function:

def no_longer_anonymous():
x = 1
return vars()

f(**no_longer_anonymous())


Yes, but that does away with the trailing suite definition of the bindings from the pov of f ;-)

BTW, I hope you will read my latest post replying to Kay Schluehr, where I propose some different
spellings ;-)

f():
x = 1

would be spelled

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

or could also be

f(x=x) where:
x = 1

"::" is a unary suite operator that returns an ordered vars().items() representing the net bindings made
in the suite (i.e. del <name> will remove a binding just as for vars()). ::<suite> is a first class expression.

items = ::
x = 1
y = 2
print items => (('x', 1), ('y', 2))

"where:" is an expression trailer introducing a suite like :: except that the bindings are used to evaluate
the names in the expression that the "where:" trails, not to produce an items() tuple.

See the other post replying to Kay for more, superseding some things in my reply to you ;-)

Regards,
Bengt Richter
Jul 19 '05 #18

P: n/a
On Sat, 16 Apr 2005 13:58:38 -0700, Brian Sabbey <sa****@u.washington.edu> wrote:

[...]

Yes, my description of the syntax was ambiguous. To clarify, I intended
the syntax to be backwardly compatible. That is, one would not be able to
use a suite to define keywords if there already exists a suite for other
reasons. So, one would not be able to use a suite to pass keywords to 'f'
in this situation:

if f():
x = 1

This code should behave exactly as it does now.

I agree that the ellipsis idea probably makes the code more readable, and
it may be a good idea to have them for that reason. However, ellipses are
not necessary as a way to disambiguate the syntax; all statements
containing suites currently begin with a keyword, and keyword suites would
not.

Using my expression where: trailer, the above if could be spelled

if f(x) where: x=1: # where:<suite> acts like '' other than its semantics.
do_something()

I was debating whether to use a where: that applied to a whole previous statement and its suite,
indenting as if the where were a following statment, e.g.,

if f(x):
do_something()
where:
x = 1

But I thought that could get too far away, and not cover many use cases that could be done
other ways. The thing that where does though is create a transient namespace for the suite
bindings, so they don't clobber the calling namespace the way just prefixing a setup would

x = 1 # clobber x
if f(x):
do_something()

Shoot, I just has another idea about the ::<suite> expression -- instead of returning a tuple,
it could return an order-maintaining subtype of dict with methods for items(), keys() and values()
and that would make better spellings for many examples in Kay's post ;-/

Also suite-based keyword calling would just become

f(10, 4, **:: # note ease of including other parameters if part of the signature
x = 1
y = 2 )

and you could do
print (::
x = 1
y = 2
).keys()
=> ['x', 'y']

or call foo
foo(self, whatever, *(::
x = 1
y = 2).values())

Oh well, that's the way ideas evolve ;-)

Regards,
Bengt Richter
Jul 19 '05 #19

P: n/a
On Sat, 16 Apr 2005 14:01:56 -0700, Brian Sabbey <sa****@u.washington.edu> wrote:
Reinhold Birkenfeld wrote:
Brian Sabbey wrote:
Here is a pre-PEP for what I call "suite-based keyword arguments". The
mechanism described here is intended to act as a complement to thunks.
Please let me know what you think.

Suite-Based Keyword Arguments
-----------------------------

Passing complicated arguments to functions is currently awkward in Python.
For example, the typical way to define a class property winds up polluting
the class's namespace with the property's get/set methods. By allowing
keyword arguments to be defined in a suite following a function call,
complicated arguments can be passed in a cleaner, easier way.

Examples
========

Using suite-based keyword arguments, the code

f(x = 1)

is equivalent to

f():
x = 1
Pretty cool, but it interferes with current suites.

How would you write

if f(x=1):
print "yes"

using suite-based keyword args?

Reinhold

if f(x=1) where: x=23:
print "yes"

"where:" expression trailer intoduces a suite whose net bindings are used to evaluate the names
in the expression it trails, which means the calling parameters, if the expression is a call.
Syntacticaly where:<suite> should be equivalent to '' other than its name binding effect (which
is only for the call -- i.e.,
x = 123
foo(x) where: x=1 # => foo(1)
print x # => 123
You wouldn't be able to use suite keywords in that situation. Also, one
would not be able to use suite keywords when there is more than one
function call on the same line:

y = f()*g():
x = 1 # ?? not allowed
Stretching for it, using my latest and greatest ;-)

y = f(**::
x = 1
y = 'y for f'
)*g(**::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)

Note that there is no problem adding other parameters, because ::<suite> is just
a unary expression returning dict subtype instance, e.g.,

y = f(11,22,**::
x = 1
y = 'y for f'
)*g(*args_from_somewhere, **::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)
This assumes that the unary ::<suite> expression returns an ordered dict subtype
instance containing the bindings created in the suite following the unary suite operator ::
E.g,
d = ::
x = 1
y = 2
print d # => {'x':1, 'y':2}

(Ignore version of previous posts where :: returned d.items() in place of d here)
There is only so much suites can do. Cases in which you want to do both
are probably far enough between that it seems acceptable to me to require
two suites:

t = f():
x = 1
if t:
y = 1
It's a little clunky, but

if self.f(self, z, *a) where:
z=123
a = getarglist(): # ':' terminates transparent where:<suite>
y = 1 # indentation as if where:<suite> were == ''

In general, I think that anything more than just a function call with an
optional assignment should be disallowed:

y = [f()]: # ? probably shouldn't be allowed
x = 1


y = [f(**:: x=1)] # sort form with single-line <suite> for ::<suite>
or
y = [f(**::
x = 1
)]

isolates the suite better, in case it has logic and fancy stuff
Regards,
Bengt Richter
Jul 19 '05 #20

P: n/a
On Sun, 17 Apr 2005 01:10:47 GMT, bo**@oz.net (Bengt Richter) wrote:
[...]

The "::" expression I'm proposing generalizes capturing suite bindings into an ordered sequence of (key,value)
tuples, like an ordered vars().items() limited to the bindings produced in the suite following "::"
Thus
items = ::
x = 1
y = [1,2]
def foo():pass

print items => (('x', 1), ('y', [1, 2]), ('foo', <function foo at 0x02EE8D14>))

Update, sorry. Galloping evolution here ;-)

The '::' unary suite operator should return an ordered dict subtype representing the bindings, so

print items => {'x':1, 'y':[1, 2], 'foo':<function foo at 0x02EE8D14>}

instead. This allows cleaner suite-based keyword calling, since no dict(::<suite>) is necessary,

so
def foo(**kw): print kw

followed by

foo(**::
x = 1
y = [1,2]
def foo():pass)

will print the same. Since ::<suite> is an expression, it can go anywhere an expression can go.
I like orthogonality ;-)

Methods allow (with order preserved from binding in suite)

(:: x=1; y=2).keys() # => ['x', 'y']
and
(:: x=1; y=2).values() # => [1, 2]
and
(:: x=1; y=2).items() # => [('x', 1), ('y', 2)]

note that :: is ;-greedy in one-line suites, so
:: x=1; y=2
is not
(:: x=1); y=2

Regards,
Bengt Richter
Jul 19 '05 #21

P: n/a
Bengt Richter wrote:
On Sun, 17 Apr 2005 01:10:47 GMT, bo**@oz.net (Bengt Richter) wrote:
[...]

The "::" expression I'm proposing generalizes capturing suite bindings into an ordered sequence of (key,value)tuples, like an ordered vars().items() limited to the bindings produced in the suite following "::"Thus
items = ::
x = 1
y = [1,2]
def foo():pass


I like this idea of "folding definitions into dicts" very much and
think that it is on the ground of suite-basing. It breaks down the
barrier between expressions and statements in Python without
annihilating it. I think it is also wise to restrict '::' to certain
accumulations. I don't like the idea of storing and dropping whole code
fragments in an irresponsible manner as Brian did for trapping the
compiler in his generator-to-function example of the thunks pre-PEP.

I think that '::' and 'where' are true and explicit representations of
the content of this proposal and be less redundant than the "as
<specifier>" syntax with it's various specifiers. Introducing '::'
would make the "folding definitions into dict" operation visible that
takes place in the machinery of the VM. Very Pythonic IMHO :-)

+1 from me for '::' and 'where'.

Regards,
Kay

Jul 19 '05 #22

P: n/a
Take a look at Nick Coglan's "with" proposal:

http://groups.google.co.uk/groups?se...t%40python.org

It addresses many of the same issues (e.g. easy definition of
properties). It is more general, though: while your proposal only
applies to keyword arguments in a function call this one can be used
to name any part of a complex expression and define it in a suite.

I think that a good hybrid solution would be to combine the "with"
block with optional use of the ellipsis to mean "all names defined in
the with block".

See also the thread resulting from Andrey Tatarinov's original
proposal (using the keyword "where"):

http://groups.google.co.uk/groups?se...individual.net
Oren
Jul 19 '05 #23

P: n/a
On 16 Apr 2005 23:06:10 -0700, or**@REMOVETHIS1.hishome.net (Oren Tirosh) wrote:
Take a look at Nick Coglan's "with" proposal:

http://groups.google.co.uk/groups?se...t%40python.org

It addresses many of the same issues (e.g. easy definition of
properties). It is more general, though: while your proposal only
applies to keyword arguments in a function call this one can be used
to name any part of a complex expression and define it in a suite.

I think that a good hybrid solution would be to combine the "with"
block with optional use of the ellipsis to mean "all names defined in
the with block".

See also the thread resulting from Andrey Tatarinov's original
proposal (using the keyword "where"):

http://groups.google.co.uk/groups?se...individual.net

Apologies for lack of attibution, Andrey. And I'm not sure I used your "where" properly just recently.
I added it to some other stuff in haste, without actually remembering exactly where it came from,
believe it or not, even though I got heavily into it in that thread. Somewhat disturbing memory lapse ;-/
I need some sleep ;-/

Regards,
Bengt Richter
Jul 19 '05 #24

P: n/a
Bengt Richter wrote:
Stretching for it, using my latest and greatest ;-)

y = f(**::
x = 1
y = 'y for f'
)*g(**::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)

Note that there is no problem adding other parameters, because ::<suite> is just
a unary expression returning dict subtype instance, e.g.,

y = f(11,22,**::
x = 1
y = 'y for f'
)*g(*args_from_somewhere, **::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)


You know that this is dead ugly?

The real ``problem'' (if you see one) is that the indentation syntax
doesn't allow for suites in expressions.

Reinhold
Jul 19 '05 #25

P: n/a
Oren Tirosh wrote:
Take a look at Nick Coglan's "with" proposal:

http://groups.google.co.uk/groups?se...t%40python.org

It addresses many of the same issues (e.g. easy definition of
properties). It is more general, though: while your proposal only
applies to keyword arguments in a function call this one can be used
to name any part of a complex expression and define it in a suite.

I think that a good hybrid solution would be to combine the "with"
block with optional use of the ellipsis to mean "all names defined in
the with block".

See also the thread resulting from Andrey Tatarinov's original
proposal (using the keyword "where"):

http://groups.google.co.uk/groups?se...individual.net


Thanks for the links. I wasn't aware of that proposal.

I agree that a hybrid solution is probably the way to go.

Does anyone know if the 'where' keyword is only for readability (or does
it disambiguate the syntax in some situations)? I think I prefer leaving
it off.

Maybe using '**' would be better than '...' since it already is used to
indicate keyword arguments. Example:

class C(object):
x = property(**):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x
-Brian
Jul 19 '05 #26

P: n/a
On Sun, 17 Apr 2005 15:25:04 +0200, Reinhold Birkenfeld <re************************@wolke7.net> wrote:
Bengt Richter wrote:
Stretching for it, using my latest and greatest ;-)

y = f(**::
x = 1
y = 'y for f'
)*g(**::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)

Note that there is no problem adding other parameters, because ::<suite> is just
a unary expression returning dict subtype instance, e.g.,

y = f(11,22,**::
x = 1
y = 'y for f'
)*g(*args_from_somewhere, **::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)
You know that this is dead ugly?

What aspect in particular? I.e., does this (currently legal) look prettier:

y = f(11,22, **dict(
x = 1,
y = 'y for f'
))*g(*args_from_somewhere, **dict(
x = 'x for g',
y = 'y for g',
foo = lambda: return 'foo for g'
))

Can you express the same semantics in a prettier way?

To boil it down, doesn't a suite bindings expression like

d = ::
x = 1
y = 'y for f'

(which in this case doesn't even need parens) seem prettier than

d = dict(
x = 1,
y = 'y for f'
)

to you, especially given that (:: ...) gives you the power
of full suite syntax to create bindings
any way you want[1], not just keyword=<expression> ?
(and you can leave out the commas ;-)

[1] I.e., this should work to extend the power of the type expression in a way
that shows what you can't do with dict(...) ;-)

type('C', (), ::
def __repr__(self):
return '<alternatively-created-class-object at %08x>'% (hex(id(self)&(2L**32-1))
def cname(self): return type(self).__name__
classvar = 123
# ... anything you can do in a class definition body
)

IMO that's pretty clean.

The real ``problem'' (if you see one) is that the indentation syntax
doesn't allow for suites in expressions.


I was trying to solve that "problem" with my "suite expressions" ;-)

::<suite> # suite bindings expression (as ordered dict)
def(<arglist>):<suite> # anonymous def
(<arglist>):<suite> # thunk (anonymous callable suite sharing local namespace)

I think suite indentation rules for suite expressions are not that hard, once you decide
to deal with it as a separate indentation space from outside the expression. That's already
done to allow multiline expressions without indentation interpretation inside bracketed expressions.
This is just adding indentation processing within certain types of expressions ("suite expressions" ;-)

For the most part I like indentation syntax very well, and
I suspect that if there were optional brackets, you would still be indenting
for clarity, so the chances are the bracket version of the above would
mainly add bracket noise to something close to the above.

Regards,
Bengt Richter
Jul 19 '05 #27

P: n/a
Brian Sabbey wrote:
Does anyone know if the 'where' keyword is only for readability (or does it
disambiguate the syntax in some situations)? I think I prefer leaving it
off.


To answer my own question, I see by reading the where threads that using
the 'where' keyword allows things such as:

# Design by contract (from Nick Coghlan)
@dbc(pre, post)
def foo():
pass
with:
def pre():
pass
def post():
pass
Jul 19 '05 #28

P: n/a
Brian Sabbey wrote:
Maybe using '**' would be better than '...' since it already is used to
indicate keyword arguments. Example:

class C(object):
x = property(**):
doc = "I'm the 'x' property."
def fget(self):
return self.__x
def fset(self, value):
self.__x = value
def fdel(self):
del self.__x


Looks good to me. You should update the pre-PEP and submit it again to
the list.

This syntax might also be a good replacement for event handling when
lambda goes away (as Guido announced in his PyCon 2005 keynote.)

button = Button(self, "Push me")
button.addHandlers(**):
def onmouseover(event):
self.textBox.setText("Are you going to push me?")
def onmouseout(event):
self.textBox.setText("Too shy. Goodbye.")
def onclick(event):
self.textBox.setText("Ouch!")
oncontextmenu = self.oncontextmenu

Shane
Jul 19 '05 #29

P: n/a
Bengt Richter wrote:
On Sun, 17 Apr 2005 15:25:04 +0200, Reinhold Birkenfeld <re************************@wolke7.net> wrote:
Note that there is no problem adding other parameters, because ::<suite> is just
a unary expression returning dict subtype instance, e.g.,

y = f(11,22,**::
x = 1
y = 'y for f'
)*g(*args_from_somewhere, **::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)


You know that this is dead ugly?

What aspect in particular?


The '**::', for example. I would surely prefer a keyword instead of '::'.
I.e., does this (currently legal) look prettier:

y = f(11,22, **dict(
x = 1,
y = 'y for f'
))*g(*args_from_somewhere, **dict(
x = 'x for g',
y = 'y for g',
foo = lambda: return 'foo for g'
))
No, it doesn't. And I surely wouldn't write such code.

y = (f(11, 22, x=1, y='y for f') *
g(*args_from_somewhere, x='x for g', y='y for g', foo=lambda: return 'foo for g'))

or, if you tolerate more lines,

y = (f(11, 22, x=1, y='y for f') *
g(*args_from_somewhere,
x='x for g', y='y for g',
foo=lambda: return 'foo for g'))

would be my current way to express this. But still, the less lines,
the less confusing it is.
Can you express the same semantics in a prettier way?

To boil it down, doesn't a suite bindings expression like

d = ::
x = 1
y = 'y for f'

(which in this case doesn't even need parens) seem prettier than

d = dict(
x = 1,
y = 'y for f'
)

to you, especially given that (:: ...) gives you the power
of full suite syntax to create bindings
any way you want[1], not just keyword=<expression> ?
(and you can leave out the commas ;-)
I understand the general idea, but still I don't like the idea of "suite expressions".
My main concern is the following: After a suite expression, where does code
follow?

As in your example:

y = f(**::
x = 1 # indented one level, as indents can go any number of spaces
) # indented one level too, but differently (currently an IndentantionError)
[1] I.e., this should work to extend the power of the type expression in a way
that shows what you can't do with dict(...) ;-)

type('C', (), ::
def __repr__(self):
return '<alternatively-created-class-object at %08x>'% (hex(id(self)&(2L**32-1))
def cname(self): return type(self).__name__
classvar = 123
# ... anything you can do in a class definition body
)

IMO that's pretty clean.


Uses are neat, i concur.
The real ``problem'' (if you see one) is that the indentation syntax
doesn't allow for suites in expressions.


I was trying to solve that "problem" with my "suite expressions" ;-)

::<suite> # suite bindings expression (as ordered dict)
def(<arglist>):<suite> # anonymous def
(<arglist>):<suite> # thunk (anonymous callable suite sharing local namespace)

I think suite indentation rules for suite expressions are not that hard, once you decide
to deal with it as a separate indentation space from outside the expression. That's already
done to allow multiline expressions without indentation interpretation inside bracketed expressions.
This is just adding indentation processing within certain types of expressions ("suite expressions" ;-)

For the most part I like indentation syntax very well, and
I suspect that if there were optional brackets, you would still be indenting
for clarity, so the chances are the bracket version of the above would
mainly add bracket noise to something close to the above.


I don't say brackets are better, but the problem of where to put the following code
is tricky.

Reinhold
Jul 19 '05 #30

P: n/a
On Mon, 18 Apr 2005 12:50:24 +0200, Reinhold Birkenfeld
<re************************@wolke7.net> wrote:
y = (f(11, 22, x=1, y='y for f') *
g(*args_from_somewhere,
x='x for g', y='y for g',
foo=lambda: return 'foo for g'))

would be my current way to express this. But still, the less lines,
the less confusing it is.


I would probably do it this way.

y = f(11, 22, x=1, y='y for f') \
* g( *args_from_somewhere,
x='x for g',
y='y for g',
foo=lambda: return 'foo for g' )

I tend to put the opperators on the left for continued lines. It's
nice visual que to whats happening.

if (a==1
or b==2
or c==3):
x = ( 1.333333333333
+ the_last_value_i_needed
+ the_first_value_i_started_with
+ another_long_name_for_something )

This subject really hasn't been a problem for me. So I really don't
see the point of adding a new syntax.

And this works on the def side.

def f( first,
second,
x=0,
y='' ):
#
# rest of body
#

So is this new syntax just a way to keep the '()'s closer together?

Cheers,
Ron

Jul 19 '05 #31

P: n/a
On Mon, 18 Apr 2005 12:50:24 +0200, Reinhold Birkenfeld <re************************@wolke7.net> wrote:
Bengt Richter wrote:
On Sun, 17 Apr 2005 15:25:04 +0200, Reinhold Birkenfeld <re************************@wolke7.net> wrote:
Note that there is no problem adding other parameters, because ::<suite> is just
a unary expression returning dict subtype instance, e.g.,

y = f(11,22,**::
x = 1
y = 'y for f'
)*g(*args_from_somewhere, **::
x = 'x for g'
y = 'y for g'
def foo(): return 'foo for g'
)

You know that this is dead ugly?

What aspect in particular?


The '**::', for example. I would surely prefer a keyword instead of '::'.


I thought it was concise and mnemonic, in that ':' already introduces suites, and '::'
introduces exactly the same thing, only processing it differently, which is suggested
concisely by '::' being different from ':' ;-)
I.e., does this (currently legal) look prettier:

y = f(11,22, **dict(
x = 1,
y = 'y for f'
))*g(*args_from_somewhere, **dict(
x = 'x for g',
y = 'y for g',
foo = lambda: return 'foo for g'
))
No, it doesn't. And I surely wouldn't write such code.

y = (f(11, 22, x=1, y='y for f') *
g(*args_from_somewhere, x='x for g', y='y for g', foo=lambda: return 'foo for g'))

or, if you tolerate more lines,

y = (f(11, 22, x=1, y='y for f') *
g(*args_from_somewhere,
x='x for g', y='y for g',
foo=lambda: return 'foo for g'))

would be my current way to express this. But still, the less lines,
the less confusing it is.

Chacun a son gout ;-)
Can you express the same semantics in a prettier way?

To boil it down, doesn't a suite bindings expression like

d = ::
x = 1
y = 'y for f'

(which in this case doesn't even need parens) seem prettier than

d = dict(
x = 1,
y = 'y for f'
)

to you, especially given that (:: ...) gives you the power
of full suite syntax to create bindings
any way you want[1], not just keyword=<expression> ?
(and you can leave out the commas ;-)


I understand the general idea, but still I don't like the idea of "suite expressions".
My main concern is the following: After a suite expression, where does code
follow?

As in your example:

y = f(**::
x = 1 # indented one level, as indents can go any number of spaces
) # indented one level too, but differently (currently an IndentantionError)

I don't understand your example. Think of it as a triple quoted string, except that it opens
with :: and doesn't require \ to ignore the first blank line, and it closes with dedent or
a closing bracket that was not opened in the "string".
That closing paren doesn't belong to the :: suite (having been opened outside the suite).
Therefore, no matter where it appears, it will end the suite, and play its own role in
matching its partner (right after f here).

If you parenthesize you are fully free to indent your first line anywhere, e.g. (perversely)
y = f(**(:: # note paren
x = 1
) # blank line with 7 spaces ends the suite
# you can't get left of the reference indentation here, so it's
# good that ')' ends the suite ;-)
) # closes f( -- legal at any indentation, since we're inside an open bracket

If you don't parenthesize, your suite will end where a normal if x: suite would end by dedent
Note that
if x:
z=2
is a syntax error, and you would expect the same with
x = ::
z = 2
if :: required something on the next line, but unlike an if with no inline suite, :: doesn't require it,
and just sees that z is at or left of the existing indentation of x, so the z is a dedent ending a blank suite,
and z better line up with something, as in

if x:
x = :: # blank suite
z = 2

So you can write
d1 = ::
x = 1
d2 = :: x=2
d2 = ::
def foo(): pass

and expect what you'd expect if you were me ;-)
BTW, surrounding brackets such as f(...) do not do away with the indentation rules
_within a_ :: suite, they just let you start it where you want.
[1] I.e., this should work to extend the power of the type expression in a way
that shows what you can't do with dict(...) ;-)

type('C', (), ::
def __repr__(self):
return '<alternatively-created-class-object at %08x>'% (hex(id(self)&(2L**32-1))
def cname(self): return type(self).__name__
classvar = 123
# ... anything you can do in a class definition body
)

IMO that's pretty clean.
Uses are neat, i concur.

Maybe I can win you over ;-)
The real ``problem'' (if you see one) is that the indentation syntax
doesn't allow for suites in expressions.


I was trying to solve that "problem" with my "suite expressions" ;-)

::<suite> # suite bindings expression (as ordered dict)
def(<arglist>):<suite> # anonymous def
(<arglist>):<suite> # thunk (anonymous callable suite sharing local namespace)

I think suite indentation rules for suite expressions are not that hard, once you decide
to deal with it as a separate indentation space from outside the expression. That's already
done to allow multiline expressions without indentation interpretation inside bracketed expressions.
This is just adding indentation processing within certain types of expressions ("suite expressions" ;-)

For the most part I like indentation syntax very well, and
I suspect that if there were optional brackets, you would still be indenting
for clarity, so the chances are the bracket version of the above would
mainly add bracket noise to something close to the above.


I don't say brackets are better, but the problem of where to put the following code
is tricky.

Why is it more tricky than the suite of if x: ?
And when can't you easily resolve a doubt with explicit parens?

Regards,
Bengt Richter
Jul 19 '05 #32

This discussion thread is closed

Replies have been disabled for this discussion.