
Maybe something like this would be nice: xdef myprop('myprop docstring') [property]: def __get__(self): ...body... def __set__(self, value): ...body... xdef frame1() [SunkenFrame]: xdef button1('OK') [Button]: def ClickEvent(): ...body... def GotFocus(): ...body... MouseoverText = 'Hello!' xdef text1(datasource=xyz) [TextBox]: pass xdef klass(base1, base2) [interface1, interface2]: ...class body... This is almost exactly what Arne Koewing posted: blockdef myprop [property]: def __get__(self): ... def __set__(self, value): ... def __delete__(self): ... Except I tried to make it look a bit more like 'def'. Obviously, this would go hand-in-hand with 'def' being extended to allow a list of modifiers at the end, like this: def name(args) [staticmethod]: The general syntax for 'xdef' would be something like: xdef name(arg1, arg2, kw_arg1=x, kw_arg2=y) [mod1, mod2]: ...class-like body... So this would work like: name = mod2(mod1(name, args, kw_args, dict)) I guess args and kw_args would work something like how 'bases' are collected in class definitions before being passed to metaclass __new__ and __init__. 'xdef' could return a class just as well as a property: xdef klass(base1, base2) [interface1, interface2]: ...class body... 'interface1','interface2' would have to be clever about sometimes being passed a class and sometimes being passed the tuple (name, args, kw_args, dict). In general, 'xdef' would allow metaclass-like processing on things that are not necessarily a class. Problems: (1) The main problem is that 'xdef' makes things that are pretty close to being classes. So why not just use classes? (2) Also 'xdef' is pointless without [mod1, mod2] xdef name(): would just assign the tuple (name, args, kw_args, dict) to name. (3) 'xdef' isn't a great name, because xdef abc(xyz): def abc(xyz): do completely different things. But the name should be short like 'def' so it doesn't draw much attention to itself, just as 'def' doesn't draw much attention to itself. So xdef myprop() [property]: the thing that sticks out is 'property' More bad stuff: xdef abc(xyz): return 7 would raise a 'SyntaxError: 'return' outside function' xdef name(arg1, kw_arg1=x) [mod1, mod2]: y = arg1 + kw_arg1 would raise NameError. Maybe Arne Koewing has a good idea not making it resemble 'def'.

But why require the empty ()? It is not a function definition. I think the property docstring should go in the usual docstring position. I also think that there's not much point in requiring __get__ etc.; get works just as wel. xdef myprop [property]: "myprop docstring" def get(self): ...
Let's discuss evaluation order a bit. It sounds like the arguments should be evaluated first, then the modifiers. (I propose that the argument list, if present, has exactly the same syntax as a function call argument list.) Then there are two possibilities for the body: (1) it could be evaluated before the xdef statement is "executed" (just as a class body); (2 or it could be compiled into a "thunk" which is somehow passed to whatever is called to implement the xdef (like a function body). Variant (2) gives much more freedom; it would allow us to create functions that can be called later, or it could be executed on the spot to yield its dictionary.
So this would work like:
name = mod2(mod1(name, args, kw_args, dict))
Variant (2) would have the thunk object instead of dict. I think a thunk should be a callable; upon execution it would return its dict of locals. Maybe if a thunk contains a 'return' statement it could return the return value instead. Maybe someone can find a use for a thunk containing 'yield', 'break' or 'continue'. Maybe all control flow in the thunk should raise an exception that the xdef can catch to decide what happens. Hm, if it did 'yield' you'd like to be able to call next() on it. So maybe there should be different types of thinks that one can distinguish.
Sure.
How does xdef know whether it's a class or not? I like it better if we're definite, and choose (2) always.
Because they're not classes. Let's not follow C++'s example of avoiding new keywords at all cost and stretching the meaning of some existing ones beyond the bounds of reason.
Or maybe it would be illegal, or maybe there would be some default modifier. (Like class has a default metaclass.)
Let's just say 'xdef' is just a shorthand for a keyword we haven't picked yet.
See above.
Not necessarily. Maybe the thunk can somehow keep a reference to the arguments (like nested scopes?). One think I'd like to do with extensible syntax like this (and for which xdef is a poor name) would be to define a "lock" statement, like Java's "synchronized" block. Maybe it could be written like this; I made the name after xdef optional: xdef (mylock) [synchronized]: ...block... which would mean: mylock.acquire() try: ...block... finally: mylock.release() It would be nice if control flow statements (return, break, continue) inside the block would somehow properly transfer control out of the block through the finally block, so that you could write things like def foo(): for i in sequence: xdef (mylock) [synchronized]: if ...condition...: continue ...more code... if ...condition...: break ...yet more code... if ...condition...: return 42 Only 'yield' doesn't really fit in here (like it doesn't fit in lots of places :-). Though this would look much better if synchronized came before mylock. It is also unsatisfying that you can't easily extend this to take multiple blocks. Maybe we can change the syntax back to something that started this. Instead of the xdef keyword, we'd use a colon at the end of an expression or assignment line. The grammar could be e.g. statement: (variable '=')* expression [':' suite] (Where suite is a simple statement or NEWLINE INDENT block DEDENT.) Then the locking example could be written as synchronized(mylock): ...block... This would mean synchronized(mylock)(thunk) where thunk would be a callable representing the block as before. If a variable was present it would receive the result, so that e.g. foo = property: def get(self): ... would end up meaning foo = property(thunk) which is only a very small stretch from what property currently does (it would have to do a typecheck on its argument for backwards compatibility). --Guido van Rossum (home page: http://www.python.org/~guido/)

On Wed, Jan 29, 2003, Guido van Rossum wrote:
Sure. But are you willing to put up with foo = lambda: ... ;-) -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ "Argue for your limitations, and sure enough they're yours." --Richard Bach

From: "Guido van Rossum" <guido@python.org>
Can you modify the locals of the surrounding (function) scope in the thunk, or its an anonymous closure with the current nested scopes rules (no rebinding)? I honestly find that trying to use a single extension to solve very different problems is a bad idea, e.g. currently class is semantically very different from control flow statements, the idea that a single extension can offer extensions for both up to general syntax extensibility seems far stretched. Personally I would find the addition of: 1) [] extendend function syntax to def (and possibly class and 2) 2) a statement that captures and extends what class does now ("my" proposal) 3) a 'with' statement for semantics like those of CL with- macros (Michael Hudson has some ideas on this) more pythonic. General syntax extensibility is another level of identity crisis for the language <wink>. regards

Personally I would find the addition of:
1) [] extendend function syntax to def (and possibly class and 2)
This is separate.
2) a statement that captures and extends what class does now ("my" proposal)
Can you remind me of this?
3) a 'with' statement for semantics like those of CL with- macros (Michael Hudson has some ideas on this)
I'd like to hear more about this.
more pythonic.
Pythonic is as pythonic does. Or, as was said in another thread, talk is cheap. :-)
General syntax extensibility is another level of identity crisis for the language <wink>.
Agreed. We're not going there. But I admit I'm inspired by Ruby's blocks (poorly explained though their exact semantics are in the Ruby literature I've come across). --Guido van Rossum (home page: http://www.python.org/~guido/)

2) a statement that captures and extends what class does now ("my"
From: "Guido van Rossum" <guido@python.org> proposal)
Can you remind me of this?
just kind name [ '(' expr,... ')' ] [ maybe [] extended syntax ]: suite but introduced by a new keyword KEYW-TO-BE kind name [ '(' expr,... ')' ] [ maybe [] extended syntax ]: suite I think the first approach - if possible - is better because so the syntax does not get 2nd-class status wrt 'class' .
I have attached his post on this to comp.lang.python. [Google groups seem not to have it, very strange]
Indeed <wink>, I could say the same about your up in the air description of thunk semantics and implementation. At least my cheap talk try to minimize work and disruption :-). [sorry I couldn't resist] Seriously IMO 'with' is analogous to 'for' plus generators and iterators. Generalized thunks are a very different beast, see below.
Ouch! Ruby-envy <wink>. Much of what they offer is covered in python by 'for' plus iterators and generators. So they seem to me a somehow redundant addition. Thunks really are a lot of work plus they would have confusing variable-geometry scoping rules, would need rules/support for return/break, would be easely abusable and cannot in the straightforward implemenantion case perform speed-wise like usual inline suites. So I sense there should be a very compelling case for them, which I don't see. IMHO (yes I'm repeating my self) *) a generalizion of what 'class' does [NEW-KEYW?] kind name [ '(' expr,... ')' ] [ maybe [] extended syntax ]: suite *) a 'with' statement (mesh conceptually well with the 'for' plus generators and interators approach) *) generators and iterators plus 'for' offer more or less the same functionality at a minor cost, with less conceptual confusion and disruption, have minor implemention cost and avoid adding some redundant functionaly (apart from 'class' generalization wrt to 'class'). regards.

But why require the empty ()? It is not a function definition. I think the property docstring should go in the usual docstring position. I also think that there's not much point in requiring __get__ etc.; get works just as wel. xdef myprop [property]: "myprop docstring" def get(self): ...
Let's discuss evaluation order a bit. It sounds like the arguments should be evaluated first, then the modifiers. (I propose that the argument list, if present, has exactly the same syntax as a function call argument list.) Then there are two possibilities for the body: (1) it could be evaluated before the xdef statement is "executed" (just as a class body); (2 or it could be compiled into a "thunk" which is somehow passed to whatever is called to implement the xdef (like a function body). Variant (2) gives much more freedom; it would allow us to create functions that can be called later, or it could be executed on the spot to yield its dictionary.
So this would work like:
name = mod2(mod1(name, args, kw_args, dict))
Variant (2) would have the thunk object instead of dict. I think a thunk should be a callable; upon execution it would return its dict of locals. Maybe if a thunk contains a 'return' statement it could return the return value instead. Maybe someone can find a use for a thunk containing 'yield', 'break' or 'continue'. Maybe all control flow in the thunk should raise an exception that the xdef can catch to decide what happens. Hm, if it did 'yield' you'd like to be able to call next() on it. So maybe there should be different types of thinks that one can distinguish.
Sure.
How does xdef know whether it's a class or not? I like it better if we're definite, and choose (2) always.
Because they're not classes. Let's not follow C++'s example of avoiding new keywords at all cost and stretching the meaning of some existing ones beyond the bounds of reason.
Or maybe it would be illegal, or maybe there would be some default modifier. (Like class has a default metaclass.)
Let's just say 'xdef' is just a shorthand for a keyword we haven't picked yet.
See above.
Not necessarily. Maybe the thunk can somehow keep a reference to the arguments (like nested scopes?). One think I'd like to do with extensible syntax like this (and for which xdef is a poor name) would be to define a "lock" statement, like Java's "synchronized" block. Maybe it could be written like this; I made the name after xdef optional: xdef (mylock) [synchronized]: ...block... which would mean: mylock.acquire() try: ...block... finally: mylock.release() It would be nice if control flow statements (return, break, continue) inside the block would somehow properly transfer control out of the block through the finally block, so that you could write things like def foo(): for i in sequence: xdef (mylock) [synchronized]: if ...condition...: continue ...more code... if ...condition...: break ...yet more code... if ...condition...: return 42 Only 'yield' doesn't really fit in here (like it doesn't fit in lots of places :-). Though this would look much better if synchronized came before mylock. It is also unsatisfying that you can't easily extend this to take multiple blocks. Maybe we can change the syntax back to something that started this. Instead of the xdef keyword, we'd use a colon at the end of an expression or assignment line. The grammar could be e.g. statement: (variable '=')* expression [':' suite] (Where suite is a simple statement or NEWLINE INDENT block DEDENT.) Then the locking example could be written as synchronized(mylock): ...block... This would mean synchronized(mylock)(thunk) where thunk would be a callable representing the block as before. If a variable was present it would receive the result, so that e.g. foo = property: def get(self): ... would end up meaning foo = property(thunk) which is only a very small stretch from what property currently does (it would have to do a typecheck on its argument for backwards compatibility). --Guido van Rossum (home page: http://www.python.org/~guido/)

On Wed, Jan 29, 2003, Guido van Rossum wrote:
Sure. But are you willing to put up with foo = lambda: ... ;-) -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ "Argue for your limitations, and sure enough they're yours." --Richard Bach

From: "Guido van Rossum" <guido@python.org>
Can you modify the locals of the surrounding (function) scope in the thunk, or its an anonymous closure with the current nested scopes rules (no rebinding)? I honestly find that trying to use a single extension to solve very different problems is a bad idea, e.g. currently class is semantically very different from control flow statements, the idea that a single extension can offer extensions for both up to general syntax extensibility seems far stretched. Personally I would find the addition of: 1) [] extendend function syntax to def (and possibly class and 2) 2) a statement that captures and extends what class does now ("my" proposal) 3) a 'with' statement for semantics like those of CL with- macros (Michael Hudson has some ideas on this) more pythonic. General syntax extensibility is another level of identity crisis for the language <wink>. regards

Personally I would find the addition of:
1) [] extendend function syntax to def (and possibly class and 2)
This is separate.
2) a statement that captures and extends what class does now ("my" proposal)
Can you remind me of this?
3) a 'with' statement for semantics like those of CL with- macros (Michael Hudson has some ideas on this)
I'd like to hear more about this.
more pythonic.
Pythonic is as pythonic does. Or, as was said in another thread, talk is cheap. :-)
General syntax extensibility is another level of identity crisis for the language <wink>.
Agreed. We're not going there. But I admit I'm inspired by Ruby's blocks (poorly explained though their exact semantics are in the Ruby literature I've come across). --Guido van Rossum (home page: http://www.python.org/~guido/)

2) a statement that captures and extends what class does now ("my"
From: "Guido van Rossum" <guido@python.org> proposal)
Can you remind me of this?
just kind name [ '(' expr,... ')' ] [ maybe [] extended syntax ]: suite but introduced by a new keyword KEYW-TO-BE kind name [ '(' expr,... ')' ] [ maybe [] extended syntax ]: suite I think the first approach - if possible - is better because so the syntax does not get 2nd-class status wrt 'class' .
I have attached his post on this to comp.lang.python. [Google groups seem not to have it, very strange]
Indeed <wink>, I could say the same about your up in the air description of thunk semantics and implementation. At least my cheap talk try to minimize work and disruption :-). [sorry I couldn't resist] Seriously IMO 'with' is analogous to 'for' plus generators and iterators. Generalized thunks are a very different beast, see below.
Ouch! Ruby-envy <wink>. Much of what they offer is covered in python by 'for' plus iterators and generators. So they seem to me a somehow redundant addition. Thunks really are a lot of work plus they would have confusing variable-geometry scoping rules, would need rules/support for return/break, would be easely abusable and cannot in the straightforward implemenantion case perform speed-wise like usual inline suites. So I sense there should be a very compelling case for them, which I don't see. IMHO (yes I'm repeating my self) *) a generalizion of what 'class' does [NEW-KEYW?] kind name [ '(' expr,... ')' ] [ maybe [] extended syntax ]: suite *) a 'with' statement (mesh conceptually well with the 'for' plus generators and interators approach) *) generators and iterators plus 'for' offer more or less the same functionality at a minor cost, with less conceptual confusion and disruption, have minor implemention cost and avoid adding some redundant functionaly (apart from 'class' generalization wrt to 'class'). regards.
participants (4)
-
Aahz
-
Guido van Rossum
-
Manuel Garcia
-
Samuele Pedroni