Thread: Re: [Pyobjc-dev] Re: [Pythonmac-SIG] pyobjc / cocoa
Brought to you by:
ronaldoussoren
From: William D. <wdd...@ma...> - 2002-10-16 16:26:06
|
This is the best suggestion I have seen yet. On Wednesday, Oct 16, 2002, at 09:49AM, Ronald Oussoren <ous...@ci...> wrote: > [obj setObject:value forKey:key] -> obj.setObjectForKey(value, key) > |
From: Seth D. <se...@jt...> - 2002-10-16 18:58:13
|
On Wednesday, October 16, 2002, at 06:18 , Bob Savage wrote: > I just want to point out one more thing: because these are part of the > name of the method, and not truly labels, the following two methods are > distinct: > > [obj message: arg1 withFoo: arg2]; > [obj withFoo:arg2 message:arg1]; > > Those are two different methods. This means that the Seth's system > would not work at all (although I don't like it because it makes the > relation between the 'labels' and arguments less clear). I may be wrong, but I disagree with your assessment. There is only a single mapping possible from my example (although now looking at it, my example had a typo). What I meant is: rt.call(obj, "message", arg1, "arg2name", arg2); # giving us the message name = "message:arg1name:arg2name" The method 'rt.call' would take arguments [0] object to receive the message, [1] first part of the message name, [2] . Each subsequent pair of arguments is interpreted as first the next chunk of the message name and then the next part of the message arguments. Where is the ambiguity? Also, since obj is really a python wrapper class for Objective-C objects, one could probably make 'call' a method (renamed to avoid conflicts) on the wrapper class, resulting in something like: obj._call("message", arg1, "arg2name", arg2); |
From: Bob I. <bo...@ma...> - 2002-10-16 19:02:36
|
On Wednesday, Oct 16, 2002, at 14:54 America/New_York, Seth Delackner wrote: > On Wednesday, October 16, 2002, at 06:18 , Bob Savage wrote: >> I just want to point out one more thing: because these are part of >> the name of the method, and not truly labels, the following two >> methods are distinct: >> >> [obj message: arg1 withFoo: arg2]; >> [obj withFoo:arg2 message:arg1]; >> >> Those are two different methods. This means that the Seth's system >> would not work at all (although I don't like it because it makes the >> relation between the 'labels' and arguments less clear). > > I may be wrong, but I disagree with your assessment. There is only a > single mapping possible from my example (although now looking at it, > my example had a typo). What I meant is: > > rt.call(obj, "message", arg1, "arg2name", arg2); > # giving us the message name = "message:arg1name:arg2name" > > The method 'rt.call' would take arguments [0] object to receive the > message, [1] first part of the message name, [2] . Each subsequent > pair of arguments is interpreted as first the next chunk of the > message name and then the next part of the message arguments. > > Where is the ambiguity? Also, since obj is really a python wrapper > class for Objective-C objects, one could probably make 'call' a method > (renamed to avoid conflicts) on the wrapper class, resulting in > something like: > > obj._call("message", arg1, "arg2name", arg2); Surely you _could_ do something like this, relatively easily at that, but with this method you can't do any subclassing. -bob |
From: Bob S. <bob...@ma...> - 2002-10-16 20:21:06
|
On Wednesday, October 16, 2002, at 01:54 PM, Seth Delackner wrote: > On Wednesday, October 16, 2002, at 06:18 , Bob Savage wrote: > >> [obj message: arg1 withFoo: arg2]; >> [obj withFoo:arg2 message:arg1]; >> >> Those are two different methods. This means that the Seth's system >> would not work > I may be wrong, but I disagree with your assessment. There is only a > single mapping possible from my example (although now looking at it, > my example had a typo). What I meant is: > > rt.call(obj, "message", arg1, "arg2name", arg2); > # giving us the message name = "message:arg1name:arg2name" > > The method 'rt.call' would take arguments [0] object to receive the > message, [1] first part of the message name, [2] . Each subsequent > pair of arguments is interpreted as first the next chunk of the > message name and then the next part of the message arguments. > > Where is the ambiguity? Hopefully I am not misunderstanding you. If what you are saying is you could take : rt.call(obj, "message", arg1, "arg2name", arg2); and have rt.call() concatenate the strings "message" and "arg2name" (with a colon between) then converting that to the selector (like method name for the runtime) "@sel(message: arg2name)" and then do a call selector with arg1 and arg2, sure you can do that. Here is where I see the ambiguity arising: @sel is drawSelfAtPoint:withSize:color: rt.call(obj, "drawSelfAtPoint", p, "color", c, "withSize", "s") rt.call() concatenates the method name as "drawSelfAtPoint: color: withSize:". Then the runtime sends a message to the object to perform the selector "@sel (drawSelfAtPoint: color: withSize:)", and the object says, it can't. Am I understanding you correctly? Because, the way I see it, this is likely to encourage runtime errors (unknown selector). Bob |
From: Bob I. <bo...@ma...> - 2002-10-16 21:27:07
|
On Wednesday, Oct 16, 2002, at 16:20 America/New_York, Bob Savage wrote: > > On Wednesday, October 16, 2002, at 01:54 PM, Seth Delackner wrote: > >> On Wednesday, October 16, 2002, at 06:18 , Bob Savage wrote: >> >>> [obj message: arg1 withFoo: arg2]; >>> [obj withFoo:arg2 message:arg1]; >>> >>> Those are two different methods. This means that the Seth's system >>> would not work > >> I may be wrong, but I disagree with your assessment. There is only a >> single mapping possible from my example (although now looking at it, >> my example had a typo). What I meant is: >> >> rt.call(obj, "message", arg1, "arg2name", arg2); >> # giving us the message name = "message:arg1name:arg2name" >> >> The method 'rt.call' would take arguments [0] object to receive the >> message, [1] first part of the message name, [2] . Each subsequent >> pair of arguments is interpreted as first the next chunk of the >> message name and then the next part of the message arguments. >> >> Where is the ambiguity? > > Hopefully I am not misunderstanding you. If what you are saying is you > could take : > rt.call(obj, "message", arg1, "arg2name", arg2); > and have rt.call() concatenate the strings "message" and "arg2name" > (with a colon between) then converting that to the selector (like > method name for the runtime) "@sel(message: arg2name)" and then do a > call selector with arg1 and arg2, sure you can do that. > > Here is where I see the ambiguity arising: > > @sel is drawSelfAtPoint:withSize:color: > > rt.call(obj, "drawSelfAtPoint", p, "color", c, "withSize", "s") > > rt.call() concatenates the method name as "drawSelfAtPoint: color: > withSize:". Then the runtime sends a message to the object to perform > the selector "@sel (drawSelfAtPoint: color: withSize:)", and the > object says, it can't. > > Am I understanding you correctly? Because, the way I see it, this is > likely to encourage runtime errors (unknown selector). That's not a case of ambiguity, that's just Programmer Error. Unknown selector is what they *should* get for issuing the selectors in an incorrect order. Notice that he's using ordered list arguments, not dictionary arguments for his call function. -bob |
From: <bb...@ma...> - 2002-10-16 21:45:41
|
On Wednesday, October 16, 2002, at 05:27 PM, Bob Ippolito wrote: >> rt.call() concatenates the method name as "drawSelfAtPoint: color: >> withSize:". Then the runtime sends a message to the object to perform >> the selector "@sel (drawSelfAtPoint: color: withSize:)", and the >> object says, it can't. The two are identical in the context of @selector(), but not NSSelectorFromString. Odd. A bugreport.apple.com report has been filed. Consider this output: 2002-10-16 17:42:19.198 bar[9636] pathForResource:ofType:inDirectory:forLocalization: == pathForResource:ofType:inDirectory:forLocalization: 2002-10-16 17:42:19.232 bar[9636] pathForResource:ofType:inDirectory:forLocalization: != pathForResource: ofType: inDirectory: forLocalization: From this code: #import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SEL sel1 = @selector(pathForResource:ofType:inDirectory:forLocalization:); SEL sel2 = @selector(pathForResource: ofType: inDirectory: forLocalization: ); SEL sel3 = NSSelectorFromString(@"pathForResource:ofType:inDirectory:forLocalizatio n:"); SEL sel4 = NSSelectorFromString(@"pathForResource: ofType: inDirectory: forLocalization: "); if (sel1 == sel2) NSLog(@"%@ == %@", NSStringFromSelector(sel1), NSStringFromSelector(sel2)); else NSLog(@"%@ != %@", NSStringFromSelector(sel1), NSStringFromSelector(sel2)); if (sel3 == sel4) NSLog(@"%@ == %@", NSStringFromSelector(sel3), NSStringFromSelector(sel4)); else NSLog(@"%@ != %@", NSStringFromSelector(sel3), NSStringFromSelector(sel4)); [pool release]; return 0; } Seems like a bit of a discontinuity between the way the two work. >> >> Am I understanding you correctly? Because, the way I see it, this is >> likely to encourage runtime errors (unknown selector). > > That's not a case of ambiguity, that's just Programmer Error. Unknown > selector is what they *should* get for issuing the selectors in an > incorrect order. Notice that he's using ordered list arguments, not > dictionary arguments for his call function. In that you are correct -- an array of arguments could be interpreted in this fashion. However, I completely fail to see how... rt.call(obj, "drawSelfAtPoint", p, "color", c, "withSize", "s") ... is cleaner/clearer/better than... obj.drawSelfAtPoint_color_withSize_(p, c, s) b.bum |
From: Bob I. <bo...@re...> - 2002-10-16 22:10:40
|
On Wednesday, Oct 16, 2002, at 17:45 America/New_York, bb...@ma... wrote: >> >> That's not a case of ambiguity, that's just Programmer Error. >> Unknown selector is what they *should* get for issuing the selectors >> in an incorrect order. Notice that he's using ordered list >> arguments, not dictionary arguments for his call function. > > In that you are correct -- an array of arguments could be interpreted > in this fashion. > > However, I completely fail to see how... > > rt.call(obj, "drawSelfAtPoint", p, "color", c, "withSize", "s") > > ... is cleaner/clearer/better than... > > obj.drawSelfAtPoint_color_withSize_(p, c, s) It's not. Though, I can see how it'd be kinda useful in strange cases to have the "rt.call" function around. -bob |
From: <bb...@ma...> - 2002-10-16 22:16:01
|
On Wednesday, October 16, 2002, at 06:10 PM, Bob Ippolito wrote: > It's not. Though, I can see how it'd be kinda useful in strange cases > to have the "rt.call" function around. Definitely useful! In particular, if we had an objc_msgSend() equivalent available on the Python side of the bridge, it opens things up for some truly tremendous opportunities. (If you know ahead of time the type and number of arguments -- which you would given that the call is coming from Python -- then NSInvocation can be used to build a stack frame and, as such, could be used to implement a solution -- slightly inefficient, but a solution none-the-less) With objc_msgSend() around, you could do something like... objc.msgSend(Foundation.NSString, "stringWithFormat:", "Foo %d Bar %5.3f Baz %s", 10, 25.3, "bob") That is, you could call the handful of varargs methods in the various 'kits. But, more importantly, it means that you could programmatically dispatch methods from the python side using standard idioms -- something that *can* be done now, but not without a bit of pain. b.bum |
From: Seth D. <se...@jt...> - 2002-10-17 01:03:00
|
On Wednesday, October 16, 2002, at 03:10 , Bob Ippolito wrote: > > On Wednesday, Oct 16, 2002, at 17:45 America/New_York, bb...@ma... > wrote: >> However, I completely fail to see how... >> >> rt.call(obj, "drawSelfAtPoint", p, "color", c, "withSize", "s") >> >> ... is cleaner/clearer/better than... >> >> obj.drawSelfAtPoint_color_withSize_(p, c, s) > > It's not. Though, I can see how it'd be kinda useful in strange cases > to have the "rt.call" function around. I'll never 'win' this discussion, as if that is meaningful, but the syntax serves another purpose. The main reason I like it is because I don't like calling conventions that list parameter names and values in separate places. With the underscore convention, you have essentially (pseudocode): call((a,b,c), (1,2,3)) when the *meaning* is call(a=1, b=2, c=3). But I'm definitely not the target audience for pyobjc, so I would ignore all of my comments at this point. I love Python and I love Objective-C. I see no reason to write GUI Cocoa code in Python when Objective-C does it perfectly and the GUI api was meant for use with Objective-C. I thus think it would be far more useful to have a simple way to link an Objective-C nib-based GUI controlled by a Python backend, with convenience wrappers to convert complex library types like dictionaries and mutable arrays. |
From: Bill B. <bb...@co...> - 2002-10-17 16:24:37
|
On Thursday, October 17, 2002, at 12:00 PM, pyt...@py... wrote: > I'll never 'win' this discussion, as if that is meaningful, but the > syntax serves another purpose. The main reason I like it is because I > don't like calling conventions that list parameter names and values in > separate places. Agreed on conventions -- I like ObjC's and SmallTalk's calling conventions much better for exactly the reason you describe. Minor correction: There are no named parameters in Objective-C. The method "setObject:forKey:" is named "setObject:forKey:" -- not "setObject: that takes an argument called forKey:". > With the underscore convention, you have essentially > (pseudocode): > > call((a,b,c), (1,2,3)) > > when the *meaning* is > > call(a=1, b=2, c=3). The underscore convention turns... [aDict setObject: foo forKey: @"bar"] ... into ... aDict.setObject_forKey_(foo, "bar") That's it. Given that there aren't named parameters, I'm not sure what the above statement is intending to mean. > But I'm definitely not the target audience for pyobjc, so I would > ignore > all of my comments at this point. I love Python and I love > Objective-C. I see no reason to write GUI Cocoa code in Python when > Objective-C does it perfectly and the GUI api was meant for use with > Objective-C. Four big reasons to use Python: - rapid development: With Python in the mix, I can reduce the compile-run part of the edit-compile-run to almost non-existent (as soon as I get class reloading working -- haven't had time to go there). In my experience, it has *vastly* improved my productivity. - access to tools: The Python world has an awesome-- both quantity and range-- variety of tools and libraries available that may not be available directly in ObjC. By using PyObjC, I can write my UI widgets in ObjC, glue 'em together using a mix of Python and ObjC, and leverage whatever tools I need from the Python world. - efficiency of implementation: There are certain tasks that Python is incredibly well suited for; writing command line tools (getopt, modularity, etc...) and implementing/using network protocols, to name two examples. Concrete example: By switching from the WebServices API provided by Apple to the xmlrpclib provided in Python, I was able to reduce the number of lines of code in the network client portion of my Cocoa app by roughly 70% (well over several hundred lines of code). At the same time, I gain.... - portability: While the Cocoa specific bits of my app are not portable, my entire communication layer is. Since my app is a client on top of a remote server and I also needed to create a command line client for the purposes of testing and automation.... and I needed to support many platforms on everything but the GUI specific bits, I chose to implement my client library in Python. It is 100% portable-- runs everywhere-- including in my ObjC/Cocoa OS X specific GUI application.l Not only did I eliminate 70% of the client side ObjC code in my Cocoa app, but I also reduced my code duplication -- I only have to write *one* client package. > I thus think it would be far more useful to have a simple way to link > an > Objective-C nib-based GUI controlled by a Python backend, with > convenience wrappers to convert complex library types like dictionaries > and mutable arrays. I believe most of this is already done. I certainly have a complex ObjC app using a python backend/client-library to talk to the server and control the UI -- it is up and running now and works very well! Convenience wrappers are in the works. Instead of wrapping, we are thinking of simply providing a subclass of NSDictionary and NSArray that can encapsulate DictType and Array/TupleTypes respectively. That way, Python arrays and dicts will behave like normal NSArray / NSDictionary instances on the ObjC side of the bridge. (The other direction has already been bridged). b.bum |
From: Bob I. <bo...@re...> - 2002-10-17 18:01:59
|
On Thursday, Oct 17, 2002, at 12:24 America/New_York, Bill Bumgarner wrote: > > Convenience wrappers are in the works. Instead of wrapping, we are > thinking of simply providing a subclass of NSDictionary and NSArray > that can encapsulate DictType and Array/TupleTypes respectively. > That way, Python arrays and dicts will behave like normal NSArray / > NSDictionary instances on the ObjC side of the bridge. (The other > direction has already been bridged). > IMHO there should also be easy to use wrappers for NSNumber and NSData.. I use those on a pretty regular basis for stuff that needs to get serialized for DO or plists. Another extremely convenient idea would be to just make special cases for some of the most used Foundation classes such as NS[Mutable]Array, NS[Mutable]Dictionary and NSEnumerator so that you can treat them like native python objects. Possibly even NS[Mutable]String and so on. Probably wouldn't even take too long to develop, especially if it's done (at least at first) from the python end of the stick and not in ObjC. Does pyobjc do garbage collection? I'd imagine that you could have the __init__ for anything to a retain and the __del__ for anything do a release without getting in the way.. -bob |
From: Bill B. <bb...@co...> - 2002-10-17 18:29:41
|
On Thursday, October 17, 2002, at 02:01 PM, Bob Ippolito wrote: > IMHO there should also be easy to use wrappers for NSNumber and > NSData.. I use those on a pretty regular basis for stuff that needs to > get serialized for DO or plists. Another extremely convenient idea > would be to just make special cases for some of the most used > Foundation classes such as NS[Mutable]Array, NS[Mutable]Dictionary and > NSEnumerator so that you can treat them like native python objects. > Possibly even NS[Mutable]String and so on. Probably wouldn't even > take too long to develop, especially if it's done (at least at first) > from the python end of the stick and not in ObjC. Wrapping NSNumber and NSData is definitely on the radar, but there is some subtlety in how they need to be wrapped. I totally agree that they should be wrapped in some fashion. On the ObjC->Python front, do you mean: [bumbox:~] bbum% python Python 2.2 (#1, 07/14/02, 23:25:09) [GCC Apple cpp-precomp 6.14] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from Foundation import * >>> a = NSMutableArray.array() >>> d = NSMutableDictionary.dictionary() >>> a.addObject_("a") >>> a[0] 'a' >>> d['foo'] = 'bar' >>> d['baz'] = 'bob' >>> d.keys() ['baz', 'foo'] >>> d.description() '{baz = bob; foo = bar; }' >>> d.objectForKey_('baz') 'bob' >>> d['baz'] 'bob' Already in there -- just not quite complete. > Does pyobjc do garbage collection? I'd imagine that you could have > the __init__ for anything to a retain and the __del__ for anything do > a release without getting in the way.. Generally, you don't have to think about it (at least I haven't been and my apps aren't crashing -- they may be leaking like a sieve, though :-). An assignment implies a -retain and destruction of the reference implies a -release. It isn't all there yet, but I think we are fairly far down the correct path -- certainly far enough to write full featured apps with a minimum of pain. BTW: I also added this utility function to Foundation: propertyListFromPythonCollection() Which does this (in one of the examples in the pyobjc source): Converting (Python Collection): {'a': [1, 2, 3, 4], 'b': 'c', 'd': 3, 'e': None, 'f': [1, {'a': 'b', 2: 3}, [3, 4]], 'g': {'h': 'i'}, 'j': (1, 2, 3, 'k', 'l')} Converted (ObjC collection): { a = (1, 2, 3, 4); b = c; d = 3; e = <null>; f = (1, {a = b; 2 = 3; }, (3, 4)); g = {h = i; }; j = (1, 2, 3, k, l); } b.bum |
From: Ronald O. <ous...@ci...> - 2002-10-17 20:18:43
|
On Thursday, Oct 17, 2002, at 20:29 Europe/Amsterdam, Bill Bumgarner wrote: > On Thursday, October 17, 2002, at 02:01 PM, Bob Ippolito wrote: >> IMHO there should also be easy to use wrappers for NSNumber and >> NSData.. I use those on a pretty regular basis for stuff that needs >> to get serialized for DO or plists. I'd prefer not to special case Objective-C classes in the extension module. We currently do so for NSString and NSNumber, and I'd prefer to not add other exceptions. > > Wrapping NSNumber and NSData is definitely on the radar, but there is > some subtlety in how they need to be wrapped. I totally agree that > they should be wrapped in some fashion. > > On the ObjC->Python front, do you mean: > > [bumbox:~] bbum% python > Python 2.2 (#1, 07/14/02, 23:25:09) > [GCC Apple cpp-precomp 6.14] on darwin > Type "help", "copyright", "credits" or "license" for more information. > >>> from Foundation import * > >>> a = NSMutableArray.array() > >>> d = NSMutableDictionary.dictionary() > >>> a.addObject_("a") > >>> a[0] > 'a' > >>> d['foo'] = 'bar' > >>> d['baz'] = 'bob' > >>> d.keys() > ['baz', 'foo'] > >>> d.description() > '{baz = bob; foo = bar; }' > >>> d.objectForKey_('baz') > 'bob' > >>> d['baz'] > 'bob' > > Already in there -- just not quite complete. The current mechanism is a bit of a hack: the 'objc' module maintains a list of methods that are added if a selector is present in the objective-C class (e.g. if the class has 'objectForKey:' add an __getitem__ method that calls objectForKey_). This should work for most collection classes. > >> Does pyobjc do garbage collection? I'd imagine that you could have >> the __init__ for anything to a retain and the __del__ for anything do >> a release without getting in the way.. Pyobjc tries very hard to maintain correct retainCounts on the Objective-C object. In general it should not be necessary to think about this. Please tell the list if you do have to call 'retain' or 'release', upto now I've been able to find a generic solution for every instance where I had to take care of retainCounts in Python code. Ronald |
From: Bill B. <bb...@co...> - 2002-10-17 20:42:46
|
On Thursday, October 17, 2002, at 04:18 PM, Ronald Oussoren wrote: > On Thursday, Oct 17, 2002, at 20:29 Europe/Amsterdam, Bill Bumgarner > wrote: >> On Thursday, October 17, 2002, at 02:01 PM, Bob Ippolito wrote: >>> IMHO there should also be easy to use wrappers for NSNumber and >>> NSData.. I use those on a pretty regular basis for stuff that needs >>> to get serialized for DO or plists. > I'd prefer not to special case Objective-C classes in the extension > module. We currently do so for NSString and NSNumber, and I'd prefer > to not add other exceptions. NSNumber is definitely bridged from Python -> ObjC, but not the other way around (this is what caused me to say that NSNumber wasn't bridged)? >>> x = NSArray.arrayWithObject_(1) >>> x[0] <NSCFNumber objective-c instance 0xc1d0e0> >>> x.objectAtIndex_(0) <NSCFNumber objective-c instance 0xc1d0e0> I'm not implying that I think the above behavior is incorrect -- I'm not really sure if I think it is or not.... In the following, it would seem that bridging would be the right thing to do: >>> a = NSMutableArray.array() >>> a.addObject_(1) >>> a.addObject_(1) >>> a[0] <NSCFNumber objective-c instance 0xca1510> >>> a[1] <NSCFNumber objective-c instance 0xc905b0> >>> a[0] == a[1] 0 >>> a[0].isEqual_(a[1]) 1 But not always -- if the developer were to ever run into a case where the (id) of a[0] and a[1] are significant, the transparent bridging of the NSNumber->Python(int/float/long) would force the developer to go to ObjC for something that is likely trivial to implement. I remember running into this issue in the Java Bridge (and in the Tcl<->ObjC bridge I wrote in 1990/1991/1992). With all that said, I don't see any reason why NSNumber should not provide implementations for at least __eq__ and __ne__ -- and maybe even the full set?? __lt__(a, b) __le__(a, b) __eq__(a, b) __ne__(a, b) __ge__(a, b) __gt__(a, b) In any case, bridging types where the type is copied should generally be avoided. It can make it impossible to deal with certain situations where the address of the object is meaningful, but the contents are not. It can also lead to some serious inefficiency if a trip across the bridge implies a copy each time. .... response continued below .... > The current mechanism is a bit of a hack: the 'objc' module maintains > a list of methods that are added if a selector is present in the > objective-C class (e.g. if the class has 'objectForKey:' add an > __getitem__ method that calls objectForKey_). This should work for > most collection classes. This is actually a really good solution in that it greatly automates the bridging process and should work transparently with the 'no cost' bridged CFTypes. Anything that makes a copy of data as it is passed across the bridge should generally be avoided -- strings are about the only exception. Unlike the Java bridge, we have the distinct advantage of working with two relatively light weight, highly dynamic, languages on either side. Java really wants to be a closed box -- it really wants to tightly control everything passed into it and, as such, the bridge often had to copy and recreated data as it passed across (i.e. there was no way to wrap an NSMutableArray instance such that it was a subclass of Vector in any kind of an effective fashion). Python's embedding API provides for a heck of a lot more informal flexibility... b.bum |
From: Ronald O. <ous...@ci...> - 2002-10-17 21:05:50
|
On Thursday, Oct 17, 2002, at 22:42 Europe/Amsterdam, Bill Bumgarner wrote: > > NSNumber is definitely bridged from Python -> ObjC, but not the other > way around (this is what caused me to say that NSNumber wasn't > bridged)? > > >>> x = NSArray.arrayWithObject_(1) > >>> x[0] > <NSCFNumber objective-c instance 0xc1d0e0> > >>> x.objectAtIndex_(0) > <NSCFNumber objective-c instance 0xc1d0e0> Automaticly conversion in one direction is not very pretty. I prefer to add automatic conversion from NSNumber to a Python type (but I'll have to check if this is possible without loss of information). > > >>> a.addObject_(1) > >>> a.addObject_(1) > >>> a[0] > <NSCFNumber objective-c instance 0xca1510> > >>> a[1] > <NSCFNumber objective-c instance 0xc905b0> > >>> a[0] == a[1] > 0 This is a bug. a[0] implements isEqual:, this means we should automaticly add '__eq__' to the python proxy. > > But not always -- if the developer were to ever run into a case where > the (id) of a[0] and a[1] are significant, the transparent bridging of > the NSNumber->Python(int/float/long) would force the developer to go > to ObjC for something that is likely trivial to implement. This might already be a problem for strings. There is quite a large number of string constants in Cocoa, and I don't know if the identity ('pointer value') of them is significant. > With all that said, I don't see any reason why NSNumber should not > provide implementations for at least __eq__ and __ne__ -- and maybe > even the full set?? These should be added, maybe including '__int__' for transparent conversion to a Python integer if the object is passed to an extension module. > > In any case, bridging types where the type is copied should generally > be avoided. It can make it impossible to deal with certain situations > where the address of the object is meaningful, but the contents are > not. I agree. > It can also lead to some serious inefficiency if a trip across the > bridge implies a copy each time. With small values the copy is not that inefficient (the overhead of the interpreter is probably much more significant) > > .... response continued below .... > >> The current mechanism is a bit of a hack: the 'objc' module maintains >> a list of methods that are added if a selector is present in the >> objective-C class (e.g. if the class has 'objectForKey:' add an >> __getitem__ method that calls objectForKey_). This should work for >> most collection classes. > > This is actually a really good solution in that it greatly automates > the bridging process and should work transparently with the 'no cost' > bridged CFTypes. I definitly do not want to get rid automaticly adding methods, but it might be possible to replace the current implementation with a more flexible solution. As I mentioned before I do not want to add more automatic conversions because: 1. The identity of objects may be significant 2. Conversion might be inefficient (especially for collections) 3. The Objective-C objects often have a larger interface than their Python counterparts, automatic conversion would make it impossible to use the additional functionality. Ronald |
From: Jack J. <Jac...@cw...> - 2002-10-18 09:15:19
|
On Thursday, October 17, 2002, at 10:42 , Bill Bumgarner wrote: >> The current mechanism is a bit of a hack: the 'objc' module maintains >> a list of methods that are added if a selector is present in the >> objective-C class (e.g. if the class has 'objectForKey:' add an >> __getitem__ method that calls objectForKey_). This should work for >> most collection classes. > > This is actually a really good solution in that it greatly automates > the bridging process and should work transparently with the 'no cost' > bridged CFTypes. > > Anything that makes a copy of data as it is passed across the bridge > should generally be avoided -- strings are about the only exception. Now that I think about it: why should strings be an exception? Could we not create an NSString subclass (along the same lines as your ideas on dictionaries and lists) that will wrap either a Python string or a Python unicode object? Actually, two wrappers (one for strings, one for unicode) may be easier, there's a lot of code that's going to be different depending on whether the underlying object is a string or unicode. Hmm, actually we may want a whole family of wrappers so we can use Python strings to represent the whole string/data/url group. -- - Jack Jansen <Jac...@or...> http://www.cwi.nl/~jack - - If I can't dance I don't want to be part of your revolution -- Emma Goldman - |
From: Jack J. <Jac...@or...> - 2002-10-17 20:06:49
|
On donderdag, oktober 17, 2002, at 06:24 , Bill Bumgarner wrote: > Convenience wrappers are in the works. Instead of wrapping, we > are thinking of simply providing a subclass of NSDictionary and > NSArray that can encapsulate DictType and Array/TupleTypes > respectively. That way, Python arrays and dicts will behave > like normal NSArray / NSDictionary instances on the ObjC side > of the bridge. (The other direction has already been bridged). I think we should again combine forces here. At the moment we have two bridges that make the NS-objects or the CoreFoundation alter-ego's available to Python, and half a bridge the other way. The Carbon.CF module (a misnomer, it isn't Carbon-dependent, that'll be fixed) exports most of CoreFoundation's objects to Python, but at the moment it isn't complete in that you can't say obj[12] if obj as a CFArray, i.e. it just exports method calls. It does have a nifty toCF() method that takes any supported Python object (a recursive combination of dict/list/string/scalar/CFObject) and returns its CF equivalent, and each CFObject has a toPython() method that does the reverse. And due to the way Carbon.CF works you hardly ever have to call toCF(), usually if a conversion from a Python object is needed it is done automatically. Most of this module is automatically generated, so as Apple comes up with more CF objects, or these objects grow new methods, that'll be automatically incorporated. And in PyObjC we have support for using NS objects in a way that is natural to Python, i.e. you can say obj[12] here. But when I last looked PyObjC didn't handle all object types, and handled some in a slightly funny way (strings, scalars). Note that "slightly funny" is meant derogatory here, doing automatic conversion for these types is often a good idea, but may come back to haunt us now that unicode is more important, and now that a Python program may have obtained a CFString object from another source. -- - Jack Jansen <Jac...@or...> http://www.cwi.nl/~jack - - If I can't dance I don't want to be part of your revolution -- Emma Goldman - |
From: Ronald O. <ous...@ci...> - 2002-10-17 20:29:50
|
On Thursday, Oct 17, 2002, at 22:06 Europe/Amsterdam, Jack Jansen wrote: > > On donderdag, oktober 17, 2002, at 06:24 , Bill Bumgarner wrote: >> Convenience wrappers are in the works. Instead of wrapping, we are >> thinking of simply providing a subclass of NSDictionary and NSArray >> that can encapsulate DictType and Array/TupleTypes respectively. The (Objective-C) class 'OC_PythonObject' already exposes the Python C-API to Objective-C. It would be easy to make the interface for collections more like the Foundation interfaces. There is one thing that we should keep in mind: the documentation for Foundation mentions that most NS<Collection> classes are binary compatible with CF<Collection> types (Apple uses a fancy term like 'zero-cost bridging', they mean you can cast an NS<Collection>* to a CF<Collection>* and back). I've thought about adding a mechanism that automaticly converts Carbon.CF.CF<Collection> instances to Objective-C objects. This is pretty ease, but I do not have time to do this at the moment. >> That way, Python arrays and dicts will behave like normal NSArray / >> NSDictionary instances on the ObjC side of the bridge. (The other >> direction has already been bridged). > > I think we should again combine forces here. <nod> > At the moment we have two bridges that make the NS-objects or the > CoreFoundation alter-ego's available to Python, and half a bridge the > other way. > > The Carbon.CF module (a misnomer, it isn't Carbon-dependent, that'll > be fixed) exports most of CoreFoundation's objects to Python, but at > the moment it isn't complete in that you can't say obj[12] if obj as a > CFArray, i.e. it just exports method calls. It does have a nifty > toCF() method that takes any supported Python object (a recursive > combination of dict/list/string/scalar/CFObject) and returns its CF > equivalent, and each CFObject has a toPython() method that does the > reverse. And due to the way Carbon.CF works you hardly ever have to > call toCF(), usually if a conversion from a Python object is needed it > is done automatically. Given the equivalence of lots of NS<X> classes with CF<X> types the toCF() function could easily be used to implement a toObjC() function. > > And in PyObjC we have support for using NS objects in a way that is > natural to Python, i.e. you can say obj[12] here. But when I last > looked PyObjC didn't handle all object types, and handled some in a > slightly funny way (strings, scalars). Note that "slightly funny" is > meant derogatory here, doing automatic conversion for these types is > often a good idea, but may come back to haunt us now that unicode is > more important, and now that a Python program may have obtained a > CFString object from another source. The funny conversions grew up since the last time you looked at them: Unicode is handled correctly (I added this when I wanted to process keyboard events for function keys, those are unicode characters without an ASCII equivalent). Ronald |
From: <bb...@ma...> - 2002-10-16 17:02:02
|
This is exactly what the Java bridge does and it is a huge source of confusion and bugs. Most developers assume that it should be (key, value), not (value, key) -- even developers that have spent years with the ObjC version of the Foundation. In teaching WebObjects classes, I spent a very good part of my "walk around the room and help students" time fixing problems that were related to this kind of mapping across the bridge (or, in the case of pure Java version of WO, the implicit mapping as a result of the pure Java rewrite). The Objective-C APIs were very carefully designed over many years (starting in 1986). The vocabulary used by those APIs leverage the syntax of the language (and of languages like it -- see SmallTalk). Attempting to map that vocabulary straight to Java or Python results in a new API whose vocabulary is incomplete and confusing. If there are situations where the existing mapping doesn't work-- that rare case where an '_' appears in the method name other than at the beginning (I grep'd through all of the headers provided by Apple and there isn't a single case where a '_' is used anywhere but to prefix the method)-- then providing a Python accessible function that is equivalent to objc_msgSend() will fix the problem (It will also fix a couple of other problems -- like how to support varargs). b.bum On Wednesday, October 16, 2002, at 12:26 PM, William Dozier wrote: > This is the best suggestion I have seen yet. > On Wednesday, Oct 16, 2002, at 09:49AM, Ronald Oussoren > <ous...@ci...> wrote: >> [obj setObject:value forKey:key] -> obj.setObjectForKey(value, key) |