Re: [Pyobjc-dev] Bridging of Strings
Brought to you by:
ronaldoussoren
From: Ronald O. <ous...@ci...> - 2002-12-23 19:31:05
|
On Monday, Dec 23, 2002, at 16:03 Europe/Amsterdam, bb...@ma... wrote: > On Sunday, Dec 22, 2002, at 18:20 US/Eastern, David Eppstein wrote: >> Shouldn't this work? >> >> NSString.localizedCaseInsensitiveCompare_('foo','bar') >> >> When I try it I get a complaint that the argument should be an >> NSString instead of a Python string. I guess this means there is a >> signature missing somewhere? I don't understand signatures well >> enough to correct it. >> >> >> Really it would be better to be able to call >> 'foo'.localizedCaseInsensitiveCompare_('bar') >> but I can see why that's unlikely to work... > > That is exactly what you *should* be able to call but for another > problem. Actually, either form should work in the Python sense. NSString.localizedCaseInsensitiveCompare_(a, b) has some change of working in a future version, 'foo'.localizedCaseInsensitiveCompare_(b) will never work. That is, unless we change the python string type which IMHO is not advisable (and not possible: 'str.foo = 1' does not work). > > This is sort of a bug in the bridge and a feature. > > Bug: > > This.... > > NSString.localizedCaseInsensitiveCompare_('foo', 'bar') > > ... should really work, but complains about "First argument must > be an objective-C object, got 'foo'". I'm somewhat surprised that > the bridge doesn't convert 'foo' to an NSString as it hits the bridge > because it is a feature of the bridge to transparently convert Strings > to their native ObjC/Python type as they pass across the bridge. Hmm... You have a point here. The current code knows that the first argument is 'self' and assumes this is already an Objective-C object. That is easily fixed, but as you noticed below that is probably not enough to get this to work. Clickety-click... It is pretty easy. I have this working for NSString in my tree, I'll check it in later but am not completely happy with the code yet. However: >>> NSString.localizedCaseInsensitiveCompare_('foo','bar') 1 >>> NSString.localizedCaseInsensitiveCompare_('FOO', 'foo') 0 At least some methods work just fine... > > Rethinking this, the above method call may not work in some > situations. In particular, in class clusters it is often the case > that you generally interact with some private subclass. For example, > NSArray.count(someArray) will not actually do what you want because > instances of NSArray are never directly instantiated-- just private > subclasses. > > In [6]: a = NSArray.arrayWithArray_([1,2,3,4,5]) > In [7]: a.count() > Out[7]: 5 > In [8]: NSArray.count(a) > ----------------------------------------------------------------------- > ---- > ValueError Traceback (most recent call > last) > > ? > > ValueError: NSInvalidArgumentException - *** -count only defined for > abstract class. Define -[NSCFArray count]! > That's just like in 'normal' python types: If you call NSArray.count you get the count method defined by NSArray instead of the one defined by the class of your object. That is not very Objective-C-like, but this is needed to implement super(cls, self).count(). --- > > So-- given that we can't call the methods on NSString via the > class object, we really need to be able to pass an NSString across the > bridge such that it remains an NSString on the Python side. There > are a number of reasons for this-- not duplicating data and having > access to the localization methods being the primary reasons. > > A workaround (for David and others, not a recommendation for a > possible solution in the bridge): > > Create an NSBundle that contains a category or class that wraps > the methods on NSString that you need access to. I.e.... > > @implementation NSString (BridgedMethods) > + (NSComparisonResult)string: (NSString *) aString > localizedCaseInsensitiveCompare:(NSString *)bString; > { > return [aString localizedCaseInsensitiveCompare: bString]; > } > @end > > ... to be invoked [after loading] as ... > > NSString.string_localizedCaseInsensitiveCompare_('foo', 'bar') > > ... not as elegant as an instance method and not directly compatible > with the various sorting methods on Array and the like That's not really a problem, just use the strint literal "localizedCaseInsentiveCompare:" as the argument off NSArray.sortedArrayUsingSelector_. By the time strings NSArray methods touch the strings in an array they will be converted to NSString (that's even true if the NSArray is the OC_PythonArray proxy for a python sequence). Ronald |