Plea for function/method syntax sugar (PEP 318, with a different syntax)
Some time ago, mwh developed a patch that adds some syntactical sugar to def, which is equivalent to PEP 318 though it has a different and more flexible syntax... previous threads can be easily found here: http://www.google.com/search?q=+site:mail.python.org+%22meth-syntax- sugar%22 the latest version of mwh's patch is here: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff Here's a quick overview: def foo(args) [sugary, expressions, list]: pass This is equivalent to: def foo(args): pass foo = list(expressions(sugary(foo))) This evaluation order is Guido approved, though at least one person wanted it to be the other way around One would use this in scenarios such as: class FooClass(object): def className(klass) [classmethod]: return klass.__name__ or, even more importantly (to me anyway): # we would change PyObjC to make this a built-in feature.. but, for completeness: import objc def signature(sig): def _signature(fn): return objc.selector(fn, signature=sig) return _signature class FooClass(NSObject): def returnsAnInteger(self) [signature('i@:')]: return 1 def returnsVoidTakesAnInteger_(self, anInteger) [signature('v@:i')]: pass With current syntax, PyObjC is extremely cumbersome: class FooClass(NSObject): def returnsAnInteger(self): return 1 returnsAnInteger = objc.selector(returnsAnInteger, signature='i@:') def returnsVoidTakesAnInteger_(self, anInteger): pass returnsVoidTakesAnInteger_ = objc.selector(returnsVoidTakesAnInteger_, signature='v@:i') # these are actually short examples, compare to something like: # textView_completions_forPartialWordRange_indexOfSelectedItem_ Why we need this: Without it, it's hard use PyObjC correctly. ObjC selector nomenclature is extremely verbose, and your fingers hurt after a while having to type each function name three times. The function __name__ is important, because the objc.selector type has to convert it to a selector:that:uses:colons:, or else the colon:using:name: would have to be specified manually. It makes classmethod/staticmethod/etc more palatable. What the patch doesn't do: lambda is not allowed in the "sugary expressions list" there's no *expansion and it won't take an actual list so if you want a prebaked list of transformations then you'll have to roll a callable that does it such as: def prebake(*expressions): def _prebake(fn): for transformation in expressions: fn = transformation(fn) return fn return fn This syntactical sugar for def is so unbelievably important to PyObjC (and likely other projects) that I am willing to distribute my own modified version of Python if it doesn't make 2.4 (though I would probably use Stackless as the base, but that's another plea for another day). The patch looks like it still applies to CVS HEAD, but there is a little fuzz on hunk 2. I have not tested it yet, but I have tested it against CVS HEAD of the 2.3.3 based Stackless. I'm willing to help however I can in order to get this into Python 2.4. -bob
Bob Ippolito
Some time ago, mwh developed a patch that adds some syntactical sugar to def, which is equivalent to PEP 318 though it has a different and more flexible syntax...
[...]
I'm willing to help however I can in order to get this into Python 2.4.
I like Michael's patch (or rather the functionality/syntax it offers), but I'd have to admit that it's for purely theoretical "that's nice" reasons - I don't have any use cases to add to yours. I'm not entirely sure why acceptance got stalled the way it did. While I don't recall wholehearted enthusiasm, nor do I recall any other proposal getting significant support. My impression was that it ended up left hanging "because there might be something better that we're missing". The fact that nothing else has been proposed since argues either that no-one is interested enough, or that there isn't likely to be a better option found. Either way, it's probably time to reopen the issue and decide one way or the other. As well as the question of whether anyone is interested, there was also a question as to whether it is useful enough to justify the language change. Your use cases may address these issues to an extent. Finally, there was an issue with the fact that the syntax didn't handle properties, but personally, I don't see that as a major issue - properties are just so different (combining 3 separate functions) that I wouldn't expect the same syntax to help in both cases. I'd like to see this resolved one way or another, and I'm also willing to help - but I'm not sure what needs doing next. Paul. -- This signature intentionally left blank
Paul Moore
Bob Ippolito
writes: Some time ago, mwh developed a patch that adds some syntactical sugar to def, which is equivalent to PEP 318 though it has a different and more flexible syntax...
[...]
I'm willing to help however I can in order to get this into Python 2.4.
I like Michael's patch (or rather the functionality/syntax it offers), but I'd have to admit that it's for purely theoretical "that's nice" reasons - I don't have any use cases to add to yours.
I'm not entirely sure why acceptance got stalled the way it did.
[...]
Finally, there was an issue with the fact that the syntax didn't handle properties,
I think this was roughly why discussion stalled -- there was a VAST thread on all kinds of syntactical extensions (some of which, in hindsight, look pretty silly), so much so that the initial proposal got lost in the noise. Please, let's not do this again :-)
but personally, I don't see that as a major issue - properties are just so different (combining 3 separate functions) that I wouldn't expect the same syntax to help in both cases.
Yeah, my patch fails to deal with a case it wasn't ever intended to. Big deal. Cheers, mwh -- nonono, while we're making wild conjectures about the behavior of completely irrelevant tasks, we must not also make serious mistakes, or the data might suddenly become statistically valid. -- Erik Naggum, comp.lang.lisp
On Feb 19, 2004, at 5:42 AM, Paul Moore wrote:
Bob Ippolito
writes: Some time ago, mwh developed a patch that adds some syntactical sugar to def, which is equivalent to PEP 318 though it has a different and more flexible syntax...
[...]
I'm willing to help however I can in order to get this into Python 2.4.
I like Michael's patch (or rather the functionality/syntax it offers), but I'd have to admit that it's for purely theoretical "that's nice" reasons - I don't have any use cases to add to yours.
I'm not entirely sure why acceptance got stalled the way it did. While I don't recall wholehearted enthusiasm, nor do I recall any other proposal getting significant support. My impression was that it ended up left hanging "because there might be something better that we're missing". The fact that nothing else has been proposed since argues either that no-one is interested enough, or that there isn't likely to be a better option found. Either way, it's probably time to reopen the issue and decide one way or the other.
As well as the question of whether anyone is interested, there was also a question as to whether it is useful enough to justify the language change. Your use cases may address these issues to an extent.
Finally, there was an issue with the fact that the syntax didn't handle properties, but personally, I don't see that as a major issue - properties are just so different (combining 3 separate functions) that I wouldn't expect the same syntax to help in both cases.
I'd like to see this resolved one way or another, and I'm also willing to help - but I'm not sure what needs doing next.
Combining three separate functions is probably done best with a data descriptor base class, or using some naming convention and a metaclass anyway.. Also note that the patch also adds the same sugar to classes, so you could use it in lieu of metaclasses for some cases (like transforming some members that follow a naming convention into properties):
class Foo(object) [type]: ... pass ... Foo
-bob
Bob Ippolito
Also note that the patch also adds the same sugar to classes, so you could use it in lieu of metaclasses for some cases (like transforming some members that follow a naming convention into properties):
class Foo(object) [type]: ... pass ... Foo
FWIW, I'm rather less convinced this is useful. Cheers, mwh -- I sense much distrust in you. Distrust leads to cynicism, cynicism leads to bitterness, bitterness leads to the Awareness Of True Reality which is referred to by those-who-lack-enlightenment as "paranoia". I approve. -- David P. Murphy, alt.sysadmin.recovery
On Feb 19, 2004, at 12:06 PM, Michael Hudson wrote:
Bob Ippolito
writes: Also note that the patch also adds the same sugar to classes, so you could use it in lieu of metaclasses for some cases (like transforming some members that follow a naming convention into properties):
class Foo(object) [type]: ... pass ... Foo
FWIW, I'm rather less convinced this is useful.
Me too, because you can do it with metaclasses... but then again, composing metaclasses is a pain in the butt. -bob
At 05:06 PM 2/19/04 +0000, Michael Hudson wrote:
Bob Ippolito
writes: Also note that the patch also adds the same sugar to classes, so you could use it in lieu of metaclasses for some cases (like transforming some members that follow a naming convention into properties):
class Foo(object) [type]: ... pass ... Foo
FWIW, I'm rather less convinced this is useful.
class Foo(object) [instancesProvide(IFoo)]: ... is actually somewhat more useful. Right now, the packages that do this sort of thing (Zope and PyProtocols) use a pseudometaclass in order to spell it more like this: class Foo(object): protocols.advise(instancesProvide=[IFoo]) Being able to spell it the other way would allow a less "magical" implementation for various types of class metadata.
"Phillip J. Eby"
At 05:06 PM 2/19/04 +0000, Michael Hudson wrote:
Bob Ippolito
writes: Also note that the patch also adds the same sugar to classes, so you could use it in lieu of metaclasses for some cases (like transforming some members that follow a naming convention into properties):
class Foo(object) [type]: ... pass ... Foo
FWIW, I'm rather less convinced this is useful.
class Foo(object) [instancesProvide(IFoo)]: ...
is actually somewhat more useful. Right now, the packages that do this sort of thing (Zope and PyProtocols) use a pseudometaclass in order to spell it more like this:
class Foo(object): protocols.advise(instancesProvide=[IFoo])
Being able to spell it the other way would allow a less "magical" implementation for various types of class metadata.
But there is not really a dramatical advantage over this notation, with a suitable metaclass: class Foo(object): __metaclass__ = SomeMetaclass __provides__ = [IFoo] And my main question (top myself, maybe) with the change is: There should really be some killer features in 2.4 which allow to drop support for Python 2.2 and 2.3 in modules using this new syntax. None of the mentioned use cases apply to the standard library. Thomas
On Feb 19, 2004, at 2:45 PM, Thomas Heller wrote:
"Phillip J. Eby"
writes: At 05:06 PM 2/19/04 +0000, Michael Hudson wrote:
Bob Ippolito
writes: Also note that the patch also adds the same sugar to classes, so you could use it in lieu of metaclasses for some cases (like transforming some members that follow a naming convention into properties):
> class Foo(object) [type]: ... pass ... > Foo
FWIW, I'm rather less convinced this is useful.
class Foo(object) [instancesProvide(IFoo)]: ...
is actually somewhat more useful. Right now, the packages that do this sort of thing (Zope and PyProtocols) use a pseudometaclass in order to spell it more like this:
class Foo(object): protocols.advise(instancesProvide=[IFoo])
Being able to spell it the other way would allow a less "magical" implementation for various types of class metadata.
But there is not really a dramatical advantage over this notation, with a suitable metaclass:
class Foo(object): __metaclass__ = SomeMetaclass __provides__ = [IFoo]
And my main question (top myself, maybe) with the change is:
There should really be some killer features in 2.4 which allow to drop support for Python 2.2 and 2.3 in modules using this new syntax. None of the mentioned use cases apply to the standard library.
There needs to be an adapter implementation in the standard library at some point anyways (personal preference: PyProtocols). Using metaclasses is unintuitive and troublesome because of the single inheritance restriction. Try using mixins! :) PJE's workaround for this is in PyProtocols is to have the advise() function do FAR too much magic (stack introspection, I think) and implements a temporary __metaclass__ that ends up removing itself as soon as the class is created. I'm sure he would love to remove this gnarly code, and I'd love to not depend on it because it's fragile. For example, if you need a custom __metaclass__ and you accidentally put advise() before that declaration then your custom __metaclass__ gets ignored. -bob
At 08:45 PM 2/19/04 +0100, Thomas Heller wrote:
But there is not really a dramatical advantage over this notation, with a suitable metaclass:
class Foo(object): __metaclass__ = SomeMetaclass __provides__ = [IFoo]
Actually, there *is* a dramatic advantage over that notation, since the idea is to allow the object to retain its *own* metaclass, not force it to use a different one. The "magic" syntax used by Zope and PyProtocols leaves the original class definition's metaclass completely unchanged, and the class decorator syntax could do the same. I'm not really strongly arguing for class decorator syntax, though, because the "magic" approach works well enough for me. I'm just pointing out that there *is* a reasonable use case for it. (Also, the "magic" approach has an additional disadvantage, in that if someone explicitly sets __metaclass__ *after* a magic function, it will silently prevent the magic from occurring. The class decorator syntax wouldn't have this problem.) While we're on the subject of PEP 318, I'd also like to mention that I find the: def foo() as bar: ... syntax much more readable than the: def foo() [bar]: ... syntax. But I'll take whatever I can get. :)
"Phillip J. Eby"
At 08:45 PM 2/19/04 +0100, Thomas Heller wrote:
But there is not really a dramatical advantage over this notation, with a suitable metaclass:
class Foo(object): __metaclass__ = SomeMetaclass __provides__ = [IFoo]
Actually, there *is* a dramatic advantage over that notation, since the idea is to allow the object to retain its *own* metaclass, not force it to use a different one.
The "magic" syntax used by Zope and PyProtocols leaves the original class definition's metaclass completely unchanged, and the class decorator syntax could do the same.
I see, it makes sense now. Thomas
Bob Ippolito
Some time ago, mwh developed a patch that adds some syntactical sugar to def, which is equivalent to PEP 318 though it has a different and more flexible syntax... previous threads can be easily found here: http://www.google.com/search?q=+site:mail.python.org+%22meth-syntax- sugar%22 the latest version of mwh's patch is here: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff
Here's a quick overview: [snip] What the patch doesn't do: lambda is not allowed in the "sugary expressions list"
Huh? For a bunch of versions of the patch, putting lambda in the "sugary expressions list" made Python trip an assert, but I believe I fixed that in the most recent version. Or do you mean something else?
there's no *expansion and it won't take an actual list so if you want a prebaked list of transformations then you'll have to roll a callable that does it such as:
def prebake(*expressions): def _prebake(fn): for transformation in expressions: fn = transformation(fn) return fn return fn
I just don't understand what you mean here. You're contemplating def foo() [memoize, *list_of_callables]: ... Eugh!
This syntactical sugar for def is so unbelievably important to PyObjC (and likely other projects) that I am willing to distribute my own modified version of Python if it doesn't make 2.4 (though I would probably use Stackless as the base, but that's another plea for another day).
The patch looks like it still applies to CVS HEAD, but there is a little fuzz on hunk 2. I have not tested it yet, but I have tested it against CVS HEAD of the 2.3.3 based Stackless.
I'm willing to help however I can in order to get this into Python 2.4.
PEP 306 is (intended to be) a checklist of what's needed. Cheers, mwh -- ARTHUR: Why are there three of you? LINTILLAS: Why is there only one of you? ARTHUR: Er... Could I have notice of that question? -- The Hitch-Hikers Guide to the Galaxy, Episode 11
On Feb 19, 2004, at 5:58 AM, Michael Hudson wrote:
Bob Ippolito
writes: Some time ago, mwh developed a patch that adds some syntactical sugar to def, which is equivalent to PEP 318 though it has a different and more flexible syntax... previous threads can be easily found here: http://www.google.com/search?q=+site:mail.python.org+%22meth-syntax- sugar%22 the latest version of mwh's patch is here: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff
Here's a quick overview: [snip] What the patch doesn't do: lambda is not allowed in the "sugary expressions list"
Huh? For a bunch of versions of the patch, putting lambda in the "sugary expressions list" made Python trip an assert, but I believe I fixed that in the most recent version. Or do you mean something else?
Oh ok, it works, but lambda needs to go in parens. Makes sense. I tried it without parens first, thinking that the closing ] would be enough syntax for a single lambda to work, because it does for lists and function calls.
def foo(bar) [lambda a:a]: File "<stdin>", line 1 def foo(bar) [lambda a:a]: ^ SyntaxError: invalid syntax def foo(bar) [(lambda a:a)]: ...
there's no *expansion and it won't take an actual list so if you want a prebaked list of transformations then you'll have to roll a callable that does it such as:
def prebake(*expressions): def _prebake(fn): for transformation in expressions: fn = transformation(fn) return fn return fn
I just don't understand what you mean here.
You're contemplating
def foo() [memoize, *list_of_callables]: ...
Eugh!
I'm just saying.. not something I would use :)
This syntactical sugar for def is so unbelievably important to PyObjC (and likely other projects) that I am willing to distribute my own modified version of Python if it doesn't make 2.4 (though I would probably use Stackless as the base, but that's another plea for another day).
The patch looks like it still applies to CVS HEAD, but there is a little fuzz on hunk 2. I have not tested it yet, but I have tested it against CVS HEAD of the 2.3.3 based Stackless.
I'm willing to help however I can in order to get this into Python 2.4.
PEP 306 is (intended to be) a checklist of what's needed.
Looks good. I see "Certain changes may require tweaks to the library module pycblr", but google doesn't even know what or where that is. I'll go through it and make a new CVS HEAD patch as well as test additions and doc changes this weekend. However, I'm not going to deal with Jython and I obviously can't do anything about pycblr :) -bob
Bob Ippolito
PEP 306 is (intended to be) a checklist of what's needed.
Looks good. I see "Certain changes may require tweaks to the library module pycblr", but google doesn't even know what or where that is. I'll go through it and make a new CVS HEAD patch as well as test additions and doc changes this weekend. However, I'm not going to deal with Jython and I obviously can't do anything about pycblr :)
Seems to be a typo: the right spelling is pyclbr (Python class browser). Thomas
Thomas Heller
Bob Ippolito
writes: PEP 306 is (intended to be) a checklist of what's needed.
Looks good. I see "Certain changes may require tweaks to the library module pycblr", but google doesn't even know what or where that is. I'll go through it and make a new CVS HEAD patch as well as test additions and doc changes this weekend. However, I'm not going to deal with Jython and I obviously can't do anything about pycblr :)
Seems to be a typo: the right spelling is pyclbr (Python class browser).
Fixed! Cheers, mwh -- Guido (like us!) is a bit schizophrenic here: he wants to be a benevolent dictator, but also wants to treat people like grownups. This probably worked better before Python got a large American audience <0.9 wink>. -- Tim Peters, 10 Feb 2000
[Bob Ippolito] [snip]
This evaluation order is Guido approved, though at least one person wanted it to be the other way around
I can understand the desire to have it both ways. That is, while it makes sense to have functions applied in list-order, it also makes sense to have the resulting function visually in the same order. [snip some examples, a few from PyObjC] From what I understand (please correct me if I am wrong), the entirety of the PEP seeks to fix the situation where someone wants to alter a defined function, the most common case (though I've never used it) in making a methods class or static (or really instancemethod and function, if we check types in Python 2.3). Now, Bob brings this up in the context of PyObjC, and generating ':' separated naming that PyObjC needs. While I feel for him not wanting to type, and even being pained to type so much, I've never needed to do the sort of thing that the PEP or Bob offers, and don't know if it is a real syntactic gain. Certainly it makes convenient all of the examples that the PEP and Bob offer, but again, is the syntax and functionality necessarily clear? Both the PEP and Bob offer that the order of invocation of the 'translations' could be reversed, and still make sense. I think this is an example of the syntax not being clear. - Josiah
On Feb 19, 2004, at 10:53 AM, Josiah Carlson wrote:
[Bob Ippolito]
[snip]
This evaluation order is Guido approved, though at least one person wanted it to be the other way around
I can understand the desire to have it both ways. That is, while it makes sense to have functions applied in list-order, it also makes sense to have the resulting function visually in the same order.
[snip some examples, a few from PyObjC]
From what I understand (please correct me if I am wrong), the entirety of the PEP seeks to fix the situation where someone wants to alter a defined function, the most common case (though I've never used it) in making a methods class or static (or really instancemethod and function, if we check types in Python 2.3).
Yes, that's what it does, and that would be the common case.
Now, Bob brings this up in the context of PyObjC, and generating ':' separated naming that PyObjC needs. While I feel for him not wanting to type, and even being pained to type so much, I've never needed to do the sort of thing that the PEP or Bob offers, and don't know if it is a real syntactic gain. Certainly it makes convenient all of the examples that the PEP and Bob offer, but again, is the syntax and functionality necessarily clear?
It's not generating ':' separated naming that PyObjC needs. The examples I specified were annotating the functions with type information, so that they could be called from Objective C properly .. "returnsAnInteger", "returnsVoidTakesAnInteger". The metaclass for an ObjC-derived class makes sure all of the methods end up as selectors, but it can only provide "sensible defaults" for type information, and they are not always very sensible.
Both the PEP and Bob offer that the order of invocation of the 'translations' could be reversed, and still make sense. I think this is an example of the syntax not being clear.
The common case doesn't need a list, just one function, so it's not likely to confuse anyone more than iter(iterable, sentinel) does.
[raiseex(1), raiseex(2)] Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in raiseex ValueError: 1 cmp(raiseex(1), raiseex(2)) Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in raiseex ValueError: 1
I think that left to right evaluation makes the most sense, because that's what Python always does unless parentheses are involved... and that's the iteration order for sequence types. I didn't really even consider the other way, until I saw that somebody else did.. and I'd be willing to guess that it was someone who has used a lot more lisp/scheme than I have ;) -bob
Bob Ippolito
Here's a quick overview:
def foo(args) [sugary, expressions, list]: pass
This is equivalent to:
def foo(args): pass foo = list(expressions(sugary(foo)))
This evaluation order is Guido approved, though at least one person wanted it to be the other way around
One would use this in scenarios such as:
class FooClass(object): def className(klass) [classmethod]: return klass.__name__
or, even more importantly (to me anyway):
# we would change PyObjC to make this a built-in feature.. but, for # completeness: import objc def signature(sig): def _signature(fn): return objc.selector(fn, signature=sig) return _signature
class FooClass(NSObject): def returnsAnInteger(self) [signature('i@:')]: return 1 def returnsVoidTakesAnInteger_(self, anInteger) [signature('v@:i')]: pass
I was thinking of a similar usecase for ctypes, defining C callback functions. In ctypes, you would be able to write """ WndProc = WINFUNCTYPE(c_int, HWND, MSG, WPARAM, LPARAM) def my_wndproc(hwnd, msg, wParam, lParam) [WndProc]: .... """ instead of this """ WndProc = WINFUNCTYPE(c_int, HWND, MSG, WPARAM, LPARAM) def my_wndproc(hwnd, msg, wParam, lParam): .... my_wndproc = WndProc(my_wndproc) """ BTW (I have this patch not yet applied), is it possible to use more than one line, in this way? def function(arg1, arg2, arg3, arg4, arg5, arg6) [dothis, dothat, doanother]: All in all, I'm +1 on the patch. Thomas
On Feb 19, 2004, at 1:36 PM, Thomas Heller wrote:
Bob Ippolito
writes: Here's a quick overview:
def foo(args) [sugary, expressions, list]: pass
This is equivalent to:
def foo(args): pass foo = list(expressions(sugary(foo)))
[examples showing how much nicer it makes type annotation in ctypes and PyObjC]
BTW (I have this patch not yet applied), is it possible to use more than one line, in this way?
def function(arg1, arg2, arg3, arg4, arg5, arg6) [dothis, dothat, doanother]:
All in all, I'm +1 on the patch.
No, that is not valid syntax with the current patch.. you would need: def function(arg1, arg2, arg3, arg4, arg5, arg6 ) [dothis, dothat, doanother]: or def function(arg1, arg2, arg3, arg4, arg5, arg6) [ dothis, dothat, doanother]: (or some variation, that makes it obvious to Python that the def is not complete). -bob
On Wed, 2004-02-18 at 21:26, Bob Ippolito wrote:
the latest version of mwh's patch is here: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff
Does anybody else have problems applying this patch? I get: % patch < meth-syntax-sugar-3.diff patch: **** File Grammar is not a regular file -- can't patch Grammar/Grammar sure seems like a regular file to me though. Standard RH9 patch(1), v 2.5.4. Above patch snagged with wget. -Barry
Barry Warsaw wrote:
On Wed, 2004-02-18 at 21:26, Bob Ippolito wrote:
the latest version of mwh's patch is here: http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff
Does anybody else have problems applying this patch? I get:
% patch < meth-syntax-sugar-3.diff patch: **** File Grammar is not a regular file -- can't patch
Grammar/Grammar sure seems like a regular file to me though. Standard RH9 patch(1), v 2.5.4. Above patch snagged with wget.
Try patch -p0. Patch removes directory names by default.
--
Sjoerd Mullender
participants (8)
-
Barry Warsaw
-
Bob Ippolito
-
Josiah Carlson
-
Michael Hudson
-
Paul Moore
-
Phillip J. Eby
-
Sjoerd Mullender
-
Thomas Heller