Thread: [Pyobjc-dev] Default to returning (void)?
Brought to you by:
ronaldoussoren
From: b.bum <bb...@ma...> - 2004-02-16 03:41:50
|
This is going to break a few things, but better to rip off the band-aid now than wait.... Currently, if I declare a standard IB action or set method (such as the following).... def setContent_(self, someContent): print "Setting content...." self._content = someContent .... I have to immediately follow the declaration with the following ... setContent_ = selector(setContent_, signature='v@:@') ... if I wait the method to be compatible with Key/Value Observation or otherwise match the signature of the typical setter or IBAction. When PyObjC was originally written -- 1994 or so -- the NeXTSTEP standard was for Obj-C methods to default to returning (id) -- to end with 'return self;'. The goal was to support a Lisp Like method chaining of the [foo doBar] doBaz] doBob] sayFred] form. When OpenStep rolled around, the ObjC world shifted to methods defaulting to not returning anything. That is, to be declared as returning (void). This has many advantages for very little cost. In particular, it means that remote invocation models-- cross thread or inter-process-- can actually do one-way calls without having to carry a proxy back across the wire. It also means that apps didn't explode because a developer assumes 'return self' when a method really returns something else (something that happened a number of times!). Of course, with Python we have no notion of "return type". A method may or may not return anything. Right now, PyObjC assumes a return of (id). In ObjC parlance, the assumed signature prefix is '@@:'. Is there any way that we can make it a bit more natural for the developer to declare IBActions or setters in PyObjC such that the resulting methods have signature 'v@:@'? |
From: Bob I. <bo...@re...> - 2004-02-16 04:37:15
|
On Feb 15, 2004, at 10:38 PM, b.bum wrote: > > This is going to break a few things, but better to rip off the > band-aid now than wait.... > > Currently, if I declare a standard IB action or set method (such as > the following).... > > def setContent_(self, someContent): > print "Setting content...." > self._content = someContent > > .... I have to immediately follow the declaration with the following > ... > > setContent_ = selector(setContent_, signature='v@:@') > > ... if I wait the method to be compatible with Key/Value Observation > or otherwise match the signature of the typical setter or IBAction. > > When PyObjC was originally written -- 1994 or so -- the NeXTSTEP > standard was for Obj-C methods to default to returning (id) -- to end > with 'return self;'. The goal was to support a Lisp Like method > chaining of the [foo doBar] doBaz] doBob] sayFred] form. > > When OpenStep rolled around, the ObjC world shifted to methods > defaulting to not returning anything. That is, to be declared as > returning (void). This has many advantages for very little cost. > In particular, it means that remote invocation models-- cross thread > or inter-process-- can actually do one-way calls without having to > carry a proxy back across the wire. It also means that apps didn't > explode because a developer assumes 'return self' when a method really > returns something else (something that happened a number of times!). > > Of course, with Python we have no notion of "return type". A method > may or may not return anything. Right now, PyObjC assumes a return > of (id). In ObjC parlance, the assumed signature prefix is '@@:'. > > Is there any way that we can make it a bit more natural for the > developer to declare IBActions or setters in PyObjC such that the > resulting methods have signature 'v@:@'? The only way I can think of is to analyze the bytecode before wrapping functions.. >>> import dis >>> def setContent_(self, someContent): ... print "Setting content..." ... self._content = someContent ... >>> dis.dis(setContent_) 2 0 LOAD_CONST 1 ('Setting content...') 3 PRINT_ITEM 4 PRINT_NEWLINE 3 5 LOAD_FAST 1 (someContent) 8 LOAD_FAST 0 (self) 11 STORE_ATTR 2 (_content) 14 LOAD_CONST 0 (None) 17 RETURN_VALUE At least in Python 2.3.x, the only way to generate "LOAD_CONST 0 (None) / RETURN_VALUE" is either a bare return, or no return at all. If you analyze the bytecode for a function, and it has no other RETURN_VALUE pairs.. then you can safely assume that it should default to void. -bob |
From: b.bum <bb...@ma...> - 2004-02-16 05:04:17
|
On Feb 15, 2004, at 8:36 PM, Bob Ippolito wrote: > At least in Python 2.3.x, the only way to generate "LOAD_CONST 0 > (None) / RETURN_VALUE" is either a bare return, or no return at all. > If you analyze the bytecode for a function, and it has no other > RETURN_VALUE pairs.. then you can safely assume that it should default > to void. Eeeewwwww.... Nuts. Defaulting to a (void) return will break for any getter, so I can see how trying to figure this out to do the right thing would be preferable. Barring automated intelligence, being able to do something like the following would be preferable to the crypting exposed signatures we have today. def setContent_(self, someContent): print "Setting content...." self._content = someContent setContent_ = selector(setContent_, type='setter') objc.makeSetter(setContent_) # this would be even better def takeAction_(self, sender): pass takeAction_ = selector(takeAction_, type='action') |
From: Bob I. <bo...@re...> - 2004-02-16 05:11:43
|
On Feb 16, 2004, at 12:00 AM, b.bum wrote: > On Feb 15, 2004, at 8:36 PM, Bob Ippolito wrote: >> At least in Python 2.3.x, the only way to generate "LOAD_CONST 0 >> (None) / RETURN_VALUE" is either a bare return, or no return at all. >> If you analyze the bytecode for a function, and it has no other >> RETURN_VALUE pairs.. then you can safely assume that it should >> default to void. > > Eeeewwwww.... > > Nuts. Defaulting to a (void) return will break for any getter, so I > can see how trying to figure this out to do the right thing would be > preferable. Yeah, it's gross, but analyzing the bytecode *would* work ;) > Barring automated intelligence, being able to do something like the > following would be preferable to the crypting exposed signatures we > have today. > > def setContent_(self, someContent): > print "Setting content...." > self._content = someContent > setContent_ = selector(setContent_, type='setter') > objc.makeSetter(setContent_) # this would be even better > > def takeAction_(self, sender): > pass > takeAction_ = selector(takeAction_, type='action') Why not objc.getter / objc.setter / objc.action? This is really why Python needs a way to decorate functions that isn't so f*!@#!ing ugly. -bob |
From: Ronald O. <ous...@ci...> - 2004-02-16 07:51:40
|
On 16-feb-04, at 6:11, Bob Ippolito wrote: > On Feb 16, 2004, at 12:00 AM, b.bum wrote: > >> On Feb 15, 2004, at 8:36 PM, Bob Ippolito wrote: >>> At least in Python 2.3.x, the only way to generate "LOAD_CONST 0 >>> (None) / RETURN_VALUE" is either a bare return, or no return at all. >>> If you analyze the bytecode for a function, and it has no other >>> RETURN_VALUE pairs.. then you can safely assume that it should >>> default to void. >> >> Eeeewwwww.... >> >> Nuts. Defaulting to a (void) return will break for any getter, so >> I can see how trying to figure this out to do the right thing would >> be preferable. > > Yeah, it's gross, but analyzing the bytecode *would* work ;) This is a little too magic, although it is a neat hack :-) > >> Barring automated intelligence, being able to do something like the >> following would be preferable to the crypting exposed signatures we >> have today. >> >> def setContent_(self, someContent): >> print "Setting content...." >> self._content = someContent >> setContent_ = selector(setContent_, type='setter') >> objc.makeSetter(setContent_) # this would be even better >> >> def takeAction_(self, sender): >> pass >> takeAction_ = selector(takeAction_, type='action') > > Why not objc.getter / objc.setter / objc.action? This is really why > Python needs a way to decorate functions that isn't so f*!@#!ing ugly. or objc.IBAction, which has the advantage of already existing. Changing the default is unacceptable, this would break people's code without any real advantage, they would have to add annotations to the other half of their methods. The current semantics are also comptatible with Python itself. Ronald -- X|support bv http://www.xsupport.nl/ T: +31 610271479 F: +31 204416173 |
From: Michael H. <mw...@py...> - 2004-02-16 10:29:58
|
Bob Ippolito <bo...@re...> writes: > Why not objc.getter / objc.setter / objc.action? This is really why > Python needs a way to decorate functions that isn't so f*!@#!ing > ugly. I've only had a patch to do that for ... 3? ... years now. Maybe it's finally time to agitate on its behalf properly on python-dev. Cheers, mwh -- Just getting something to work usually means writing reams of code fast, like a Stephen King novel, but making it maintainable and high-quality code that really expresses the ideas well, is like writing poetry. Art is taking away. -- Erik Naggum, comp.lang.lisp |
From: Bob I. <bo...@re...> - 2004-02-16 11:03:15
|
On Feb 16, 2004, at 5:26 AM, Michael Hudson wrote: > Bob Ippolito <bo...@re...> writes: > >> Why not objc.getter / objc.setter / objc.action? This is really why >> Python needs a way to decorate functions that isn't so f*!@#!ing >> ugly. > > I've only had a patch to do that for ... 3? ... years now. Maybe it's > finally time to agitate on its behalf properly on python-dev. Sounds like a good plan, where's the patch, and does it already have a PEP? -bob |
From: Marc-Antoine P. <map...@ac...> - 2004-02-16 15:18:22
|
Le 04-02-16, =E0 00:00, b.bum a =E9crit : > Barring automated intelligence, being able to do something like the=20 > following would be preferable to the crypting exposed signatures we=20 > have today. > > def setContent_(self, someContent): > print "Setting content...." > self._content =3D someContent > setContent_ =3D selector(setContent_, type=3D'setter') > objc.makeSetter(setContent_) # this would be even better > > def takeAction_(self, sender): > pass > takeAction_ =3D selector(takeAction_, type=3D'action') ... Le 04-02-16, =E0 00:11, Bob Ippolito a =E9crit : > Why not objc.getter / objc.setter / objc.action? This is really why=20= > Python needs a way to decorate functions that isn't so f*!@#!ing ugly. I am just a clueless lurker, but +1 to having those transformations=20 sooner rather than later, with as nice a name as you all can devise. If=20= we also get syntax sugar at some point, as per Michael Hudson's post,=20 all the better, but I feel that we (PyObjC users) need a way to say=20 those things that does not depend on ObjC selector syntax. Aside: I just had a look at the Cocoa Bindings documentation, and was=20 very impressed. I do hope we will be able to exploit this from PyObjC=20 as seamlessly as possible, and if my (still very, very limited)=20 understanding of PyObjC serves me right, following the K-V standards is=20= still a stumbling block, and this would definitely help. Please correct=20= me if I got it all wrong, and it is totally unrelated after all! Marc-Antoine |
From: Ronald O. <ous...@ci...> - 2004-02-16 15:56:55
|
On 16-feb-04, at 16:15, Marc-Antoine Parent wrote: > Le 04-02-16, =E0 00:00, b.bum a =E9crit : >> def takeAction_(self, sender): >> pass >> takeAction_ =3D selector(takeAction_, type=3D'action') > > ... > Le 04-02-16, =E0 00:11, Bob Ippolito a =E9crit : >> Why not objc.getter / objc.setter / objc.action? This is really why=20= >> Python needs a way to decorate functions that isn't so f*!@#!ing=20 >> ugly. > > I am just a clueless lurker, but +1 to having those transformations=20 > sooner rather than later, with as nice a name as you all can devise.=20= > If we also get syntax sugar at some point, as per Michael Hudson's=20 > post, all the better, but I feel that we (PyObjC users) need a way to=20= > say those things that does not depend on ObjC selector syntax. I'm all for adding easy to use names instead of using selector()=20 directly, we'll have to do that anyway if we want to use syntactic=20 sugar later on. CVS will soon contain the functions that Bob proposed. > > Aside: I just had a look at the Cocoa Bindings documentation, and was=20= > very impressed. I do hope we will be able to exploit this from PyObjC=20= > as seamlessly as possible, and if my (still very, very limited)=20 > understanding of PyObjC serves me right, following the K-V standards=20= > is still a stumbling block, and this would definitely help. Please=20 > correct me if I got it all wrong, and it is totally unrelated after=20 > all! I must admit that I haven't read those documents yet, and haven't done=20= much with Cocoa Bindinds, but it is my intention that Cocoa Bindings=20 "just work" without special code in python. We're probably not there=20 yet, although Cocoa Bindings should work just fine. Ronald -- X|support bv http://www.xsupport.nl/ T: +31 610271479 F: +31 204416173 |
From: b.bum <bb...@ma...> - 2004-02-16 16:07:18
|
On Feb 16, 2004, at 7:50 AM, Ronald Oussoren wrote: > On 16-feb-04, at 16:15, Marc-Antoine Parent wrote: >> Le 04-02-16, =E0 00:00, b.bum a =E9crit : > I'm all for adding easy to use names instead of using selector()=20 > directly, we'll have to do that anyway if we want to use syntactic=20 > sugar later on. > > CVS will soon contain the functions that Bob proposed. For once, I may have managed to beat Ronald to this. Let's hope I got=20= it right. I added Accessor() to objc. Accessor is the generic term for the=20 setters and getters in Key-Value Coding. The Accessor() function tries=20= to intelligently determine if it should return the setter or getter=20 signature. I can see two problems with that: - what if it is overriding an already existing setter/getter? In that=20= case, the signature should be determined by the super. - what if the developer wants to return a scalar type? def Accessor(func): """ Return an Objective-C method object that is conformant with=20 key-value coding and key-value observing. """ argCount =3D func.func_code.co_argcount if argCount is 2: return selector(func, signature=3D"v@:@") elif argCount is 1: return selector(func, signature=3D"@@:") elif argCount is 0: raise ValueError, "Too few arguments to function '%s'. Cannot=20= create selector." % foo.func_name else: raise ValueError, "Too many arguments to function '%s'. Cannot=20= create selector." % foo.func_name |
From: Ronald O. <ous...@ci...> - 2004-02-16 18:31:06
|
On 16-feb-04, at 17:03, b.bum wrote: > On Feb 16, 2004, at 7:50 AM, Ronald Oussoren wrote: >> On 16-feb-04, at 16:15, Marc-Antoine Parent wrote: >>> Le 04-02-16, =E0 00:00, b.bum a =E9crit : >> I'm all for adding easy to use names instead of using selector()=20 >> directly, we'll have to do that anyway if we want to use syntactic=20 >> sugar later on. >> >> CVS will soon contain the functions that Bob proposed. > > For once, I may have managed to beat Ronald to this. Let's hope I got=20= > it right. You did manage to beat me. There's one thing I don't like about your=20 change: the function name, I prefer an initial lowercase letter. That=20 also reads nicer with the proposed syntax changes for properties: def objc.accessor setFoo(self, newFoo): =09 or def setFoo(self, newFoo) [objc.accessor]: I'm not yet 100% sure if I like a single function instead of a pair of=20= functions. Ronald -- X|support bv http://www.xsupport.nl/ T: +31 610271479 F: +31 204416173 |
From: b.bum <bb...@ma...> - 2004-02-16 19:23:17
|
On Feb 16, 2004, at 10:27 AM, Ronald Oussoren wrote: > You did manage to beat me. There's one thing I don't like about your > change: the function name, I prefer an initial lowercase letter. That > also reads nicer with the proposed syntax changes for properties: > > def objc.accessor setFoo(self, newFoo): > > or > def setFoo(self, newFoo) [objc.accessor]: I'm somewhat indifferent to casing on this. I chose Accessor over accessor because it matched the case of IBAction and IBOutlet. Given the usage pattern, 'accessor' works fine, too. > I'm not yet 100% sure if I like a single function instead of a pair of > functions. The KVO/KVC use 'accessor method' or 'accessor methods' to refer to both the setter and getter. I chose a single function implementation to continue that usage pattern. Personally, I like the single function pattern because it eliminates a detail from the resulting implementation; it perpetuates the notion that PyObjC's bridge should be as thin and transparent as possible. b.bum |
From: b.bum <bb...@ma...> - 2004-02-16 16:10:18
|
On Feb 16, 2004, at 7:50 AM, Ronald Oussoren wrote: >> Aside: I just had a look at the Cocoa Bindings documentation, and was >> very impressed. I do hope we will be able to exploit this from PyObjC >> as seamlessly as possible, and if my (still very, very limited) >> understanding of PyObjC serves me right, following the K-V standards >> is still a stumbling block, and this would definitely help. Please >> correct me if I got it all wrong, and it is totally unrelated after >> all! > > I must admit that I haven't read those documents yet, and haven't done > much with Cocoa Bindinds, but it is my intention that Cocoa Bindings > "just work" without special code in python. We're probably not there > yet, although Cocoa Bindings should work just fine. It mostly "just works" right now. There are a couple of areas that have been problematic in the past, but I believe they have mostly been fixed. It is on my rather long todo list to right a series of unit tests against KVO and KVC that exercise all the myriad of features thoroughly. Since that particular task coincides nicely with my day job, it may actually get done. Having a thorough test of KVO/KVC from a bridged language will actually be very helpful to me. b.bum |
From: Marc-Antoine P. <map...@ac...> - 2004-02-16 16:45:55
|
>> I must admit that I haven't read those documents yet, and haven't >> done much with Cocoa Bindinds, but it is my intention that Cocoa >> Bindings "just work" without special code in python. We're probably >> not there yet, although Cocoa Bindings should work just fine. > > It mostly "just works" right now. There are a couple of areas that > have been problematic in the past, but I believe they have mostly been > fixed. Sounds great. I did not realize this, as I had not seen any trace of the Controller classes in {Lib|Modules}/Foundation/* I have not done it yet, but I meant to attempt the Currency converter from the Bindings example in PyObjC. If I make it sometime in the next week, should it make it to the Examples? or do you have better examples in the work for controllers? Marc-Antoine |
From: b.bum <bb...@ma...> - 2004-02-16 17:05:00
|
On Feb 16, 2004, at 8:42 AM, Marc-Antoine Parent wrote: > Sounds great. I did not realize this, as I had not seen any trace of > the Controller classes in {Lib|Modules}/Foundation/* > I have not done it yet, but I meant to attempt the Currency converter > from the Bindings example in PyObjC. If I make it sometime in the next > week, should it make it to the Examples? or do you have better > examples in the work for controllers? Credit for that goes to Ronald, the transparency of the PyObjC bridge, and the brilliant engineers at Apple that built the bindings layer (I can say that because it was built before I joined that particular team :).... There wasn't any kind of special bridging required for the various Controller classes. As long as an object can do key/value coding and key/value observing, it will work with the controller layer. Automatic Key/Value observing is currently a challenge. There have been a number of patches that addressed issues with KVO and, at this point, it mostly "just works". As previously mentioned, having a set of unit tests that provide decent testing coverage is on the todo list. On the 'performance hack' front, supporting indexed accessors in an automated fashion would also be useful, but I haven't thought about how useful that might truly be or what implementation pattern should be used. As it stands, the Currency Converter should be able to be ported without much effort. I would recommend starting with the examples and docs on developer.apple.com as they are the most up to date source of info.... b.bum |
From: Marc-Antoine P. <map...@ac...> - 2004-02-17 01:08:52
|
Le 04-02-16, =E0 11:03, b.bum a =E9crit : > For once, I may have managed to beat Ronald to this. Let's hope I got=20= > it right. ... > def Accessor(func): > """ > Return an Objective-C method object that is conformant with=20 > key-value coding > and key-value observing. > """ > argCount =3D func.func_code.co_argcount > if argCount is 2: > return selector(func, signature=3D"v@:@") > elif argCount is 1: > return selector(func, signature=3D"@@:") > elif argCount is 0: > raise ValueError, "Too few arguments to function '%s'. Cannot=20= > create selector." % foo.func_name > else: > raise ValueError, "Too many arguments to function '%s'. =20 > Cannot create selector." % foo.func_name ... > I added Accessor() to objc. Accessor is the generic term for the=20 > setters and getters in Key-Value Coding. The Accessor() function=20 > tries to intelligently determine if it should return the setter or=20 > getter signature. I can see two problems with that: > On the 'performance hack' front, supporting indexed accessors in an=20 > automated fashion would also be useful, but I haven't thought about=20 > how useful that might truly be or what implementation pattern should=20= > be used. Se were you planning to have an indexedAccessor as a separate function=20= type? Because from what I read, the indexed key-value accessor methods are a=20= bit more complex, and one cannot rely on signatures alone: getters: Core: -(uint)countOf<Key> -(id)objectIn<Key>AtIndex: Optional: -(id[])get<Key>:(uint)range:(uint) setters: Core: -(void)insertObject:(id)in<Key>AtIndex: (uint) -(void)removeObjectFrom<Key>AtIndex:(uint) Optional: -(void)replaceObjectIn<Key>AtIndex:(uint)withObject:(id) So what do we do now, if we implement all of these in a Python class? Python argcount is obviously not the answer. The options I see are 1) introduce so many method types (indexedGetter, indexedInsert,=20 indexedCounter...) 2) Rely on name structures using the same conventions as objective-C 3) assume that any python collection will be handled by an attribute=20 slot It is made all the more complicated by the fact that the to-many=20 relationships in ObjC can have meta-information that declares the=20 inverse relationship between to objects. Would you want to go so far? I suggest we all think carefully about this and other KV coding issues,=20= as it might impact what ends up being the "best" solution for atomic=20 accessors. Marc-Antoine |
From: Michael H. <mw...@py...> - 2004-02-16 11:17:33
|
Bob Ippolito <bo...@re...> writes: > On Feb 16, 2004, at 5:26 AM, Michael Hudson wrote: > >> Bob Ippolito <bo...@re...> writes: >> >>> Why not objc.getter / objc.setter / objc.action? This is really why >>> Python needs a way to decorate functions that isn't so f*!@#!ing >>> ugly. >> >> I've only had a patch to do that for ... 3? ... years now. Maybe it's >> finally time to agitate on its behalf properly on python-dev. > > Sounds like a good plan, where's the patch, The patch is at http://starship.python.net/crew/mwh/hacks/meth-syntax-sugar-3.diff It has been discussed a bit on python-dev already (part of those huge threads about syntax ~9 months back); http://www.google.com/search?q=+site:mail.python.org+%22meth-syntax-sugar%22 is a good start :-) I assume that patch applies cleanly; haven't actually tried it lately. > and does it already have a PEP? It's kinda covered by PEP 318, but that advocates a different syntax variant. Cheers, mwh -- MARVIN: What a depressingly stupid machine. -- The Hitch-Hikers Guide to the Galaxy, Episode 7 |