Thread: [Pyobjc-dev] NSString & mutability
Brought to you by:
ronaldoussoren
From: Just v. R. <ju...@le...> - 2003-02-04 20:22:16
|
Someone on comp.sys.mac.programmer.help suggested a trick to find out whether an NS[CF]String is mutable or not: by comparing classForCoder to NSString. Nifty. This allowed me to patch objc_support.m so it only converts immutable strings to Python strings: Index: objc_support.m =================================================================== RCS file: /cvsroot/pyobjc/pyobjc/Modules/objc/objc_support.m,v retrieving revision 1.20 diff -c -r1.20 objc_support.m *** objc_support.m 31 Jan 2003 10:35:29 -0000 1.20 --- objc_support.m 4 Feb 2003 20:11:36 -0000 *************** *** 614,620 **** retobject = [(OC_PythonDictionary *)obj pyObject]; Py_INCREF(retobject); } ! else if ([obj isKindOfClass:[NSString class]]) { /* All string classes seem to be subclasses of NSString. * We convert to a python string where possible, and a python --- 614,621 ---- retobject = [(OC_PythonDictionary *)obj pyObject]; Py_INCREF(retobject); } ! else if ([obj isKindOfClass:[NSString class]] && ! [obj classForCoder] == [NSString class]) { /* All string classes seem to be subclasses of NSString. * We convert to a python string where possible, and a python This works nicely: >>> from Foundation import * >>> x = NSMutableString.stringWithString_("asdasd") >>> x <NSCFString objective-c instance 0x430840> >>> x.appendString_("aaa") >>> repr(x) '<NSCFString objective-c instance 0x430840>' However, str() fails: >>> str(x) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: __str__ returned non-string (type NSCFString) >>> I can't seem to find where I can repair this. Bill, this is not to say I'm _completely_ opposed to wrapping instead of converting strings, but more that I'd like to see how "partial conversion" (ie. don't convert if the string is mutable) works in practice. Just |
From: David E. <epp...@ic...> - 2003-02-04 20:33:10
|
On 2/4/03 9:21 PM +0100 Just van Rossum <ju...@le...> wrote: > Bill, this is not to say I'm _completely_ opposed to wrapping instead of > converting strings, but more that I'd like to see how "partial > conversion" (ie. don't convert if the string is mutable) works in > practice. I also feel that partial conversion is likely to be the most intuitive option. -- David Eppstein UC Irvine Dept. of Information & Computer Science epp...@ic... http://www.ics.uci.edu/~eppstein/ |
From: <bb...@ma...> - 2003-02-04 20:38:13
|
On Tuesday, Feb 4, 2003, at 15:21 US/Eastern, Just van Rossum wrote: > Someone on comp.sys.mac.programmer.help suggested a trick to find out > whether an NS[CF]String is mutable or not: by comparing classForCoder > to > NSString. Nifty. > > This allowed me to patch objc_support.m so it only converts immutable > strings to Python strings: Nice hack, but.... What about all the code that might return a mutable string depending on how the developer exercises the API? Are you willing to assume that every getter and setter that internally makes a immutable copy of the set string value? i.e. that... ... [fooObject setMyNameIs: someRandomMutableString]; return [fooObject myNameIs] ... ... that -myNameIs will return an immutable string? See this message -- it is still quite relevant. Mike Ferris is one of the guys who helped write the AppKit and Project Builder. http://www.omnigroup.com/mailman/archive/macosx-dev/2000-May/001886.html |
From: David E. <epp...@ic...> - 2003-02-04 20:49:36
|
On 2/4/03 3:38 PM -0500 bb...@ma... wrote: > On Tuesday, Feb 4, 2003, at 15:21 US/Eastern, Just van Rossum wrote: >> Someone on comp.sys.mac.programmer.help suggested a trick to find out >> whether an NS[CF]String is mutable or not: by comparing classForCoder >> to >> NSString. Nifty. >> >> This allowed me to patch objc_support.m so it only converts immutable >> strings to Python strings: > > Nice hack, but.... > > What about all the code that might return a mutable string depending on > how the developer exercises the API? Are you willing to assume that > every getter and setter that internally makes a immutable copy of the set > string value? i.e. that... If some code is going to do that, it is certainly worse to convert the mutable string to a python string, because then the converted string wouldn't see any mutations that might be made later on the objc side. I could live with not converting any NSStrings, as long as the Python side views the unconverted NSString as something that's mostly interchangeable with real str's. If there is some code that really needs its argument to be a str, one could always explicitly convert with str(), but I'd like such conversions to be rare. Just like in pure Python, where most of the time anything that obeys the list or iterator protocol can be passed in place of a list, but sometimes you need an explicit call to list(). -- David Eppstein UC Irvine Dept. of Information & Computer Science epp...@ic... http://www.ics.uci.edu/~eppstein/ |
From: Just v. R. <ju...@le...> - 2003-02-04 20:57:15
|
bb...@ma... wrote: > Nice hack, but.... > > What about all the code that might return a mutable string depending > on how the developer exercises the API? Are you willing to assume > that every getter and setter that internally makes a immutable copy > of the set string value? i.e. that... > > .... [fooObject setMyNameIs: someRandomMutableString]; return > [fooObject myNameIs] .... > > .... that -myNameIs will return an immutable string? I'm totally willing to accept a surprise like that. I don't even see the problem when using such an API from Python: you call fooObject.setMyNameIs_() with a Python string, you call myNameIs() and get a Python string. Same string, different id. No problem in Python. Can you please give an example of an _actual_ problem? I'll have a go myself: Let's assume the API does the reverse: it takes an immutable string, yet returns its internal mutable copy, although myNameIs is declared to return an NSString. Now there _is_ a surprise: instead of a 100% equivalent string we get an NSMutableString instance. Ok, a surprise, but is it so bad? If the object internally uses a mutable string, it's likely that this is clear from the nature of the object (eg. it's some sort of editor for the string). So I still think such a surprise will be rare. > See this message -- it is still quite relevant. Mike Ferris is one > of the guys who helped write the AppKit and Project Builder. > > http://www.omnigroup.com/mailman/archive/macosx-dev/2000-May/001886. > html It's an example of NSArray, which we don't convert, so we live dangerously anyway in PyObjC as we don't even have the hint from the header that we _shouldn't_ mutate even if it is mutable. Just |
From: <bb...@ma...> - 2003-02-04 21:37:07
|
On Tuesday, Feb 4, 2003, at 15:56 US/Eastern, Just van Rossum wrote: > I'm totally willing to accept a surprise like that. I don't even see > the > problem when using such an API from Python: you call > fooObject.setMyNameIs_() with a Python string, you call myNameIs() and > get a Python string. Same string, different id. No problem in Python. I'm not willing to accept a surprise like that because it will greatly reduce the value of PyObjC in quite a number of situations. This is not idle speculation. I have made the same mistake in the past [creating a bridge that was dependent on internal implementation of underlying frameworks] and it rendered the bridge [Tcl <-> ObjC, in this case] nearly useless until it was fixed -- it broke-- or sometimes didn't break-- depending on what order the user did things simply because some random bit of code somewhere chose to return *this* private subclass vs. *that* private subclass as some internal optimization hack that was *not* apparent, no relevant to, the advertised API. The fundamental problem is that partial conversion relies on the internal implementation to stay the same over time. The current behavior does not; it remains consistent. Partial conversion behavior that is dependent upon the internal implementation of 'third party' [Apple is a third party, in this case] frameworks will lead to behavior that changes over time and through factors outside of our control. More below.... > Can you please give an example of an _actual_ problem? I'll have a go > myself: Off the top of my head, no-- I can't remember a specific example. But that is mostly because I have been relying on the APIs as advertised by the classes and not their internal implementations for long enough that I haven't had this problem in a while. It *does* come up on the mailing lists on occasion, but searching for "nsmutablestring nsstring return" yields an awful lot of noise hits. > Let's assume the API does the reverse: it takes an immutable string, > yet > returns its internal mutable copy, although myNameIs is declared to > return an NSString. Now there _is_ a surprise: instead of a 100% > equivalent string we get an NSMutableString instance. Ok, a surprise, > but is it so bad? If the object internally uses a mutable string, it's > likely that this is clear from the nature of the object (eg. it's some > sort of editor for the string). So I still think such a surprise will > be > rare. I agree that the situations where this arise will be rare. But, when they do arise, the results are the absolute worst kinds of bugs in the world to fix. It breaks on customer A's computer, but not customer B's -- but they are [supposedly] identical. Oh, wait a minute, Customer B upgraded to version 1.234b of the some random plugin while customer A is still using 1.233. Another exmaple: What if Mike [who I included in this because he may have some useful input-- sorry, Mike :-] changes the implementation of TextExtras and throws an NSMutableString into some random object collection that ends up on the other side of the bridge at some point? The Python developer is screwed if there code breaks. What happens when Apple ships the 10.2.5 update and they change some random bit of internal implementation such that a method that used to return (NSMutableString*) now *always* returns (NSString*)? Assuming the PyObjC developer can figure out what is going on, are they now supposed to write OS X version specific code at the x.x.1 level? Now-- what about the developers that will be using PyObjC with multiple thousands of lines of code embedded in random frameworks across some large scale system? For them, the choice of using PyObjC now comes with the cost of having to ensure that every method that *may* return an NSMutableString* when it is declared with an NSString* return value is identified and compensated for. This is not a contrived example-- I and a number of people I have been in contact with since PyObjC became a visible project again-- have used PyObjC in this context in the past and are planning on doing so in the future [some already are]. This would be a deal killer for them. Bottom line: PyObjC -- just like the AppleScript in an AS Studio project or a good chunk of the ObjC in a pure ObjC Cocoa app -- is the glue that holds together all of the random objects in a fashion that solves whatever problem the developer is trying to address. The developer does not have full and complete control over those objects-- heck, there may be entire chunks of implementation present that their code has no awareness of whatsoever [TextExtras]. For such a system to work, the objects must be glued together as advertised by the APIs. To do otherwise will render a system that is fragile. Worse, it will create a system whose fragility is dependent upon unreasonable expectations. It is reasonable to expect-- and history indicates it is true-- that the behavior of the NSCell API will remain consistent going forward. It is unreasonable to expect that the internal implementation will remain consistent over time, yet that is exactly what a partial conversion solution expects. b.bum |
From: Just v. R. <ju...@le...> - 2003-02-04 23:28:59
|
bb...@ma... wrote: > It is unreasonable to expect that the internal implementation will > remain consistent over time, yet that is exactly what a partial > conversion solution expects. Ok, I'm about to give in. Let's focus on making NSString instances work as much as Python strings as possible. For fun, I removed the conversion, and (quite obviously) as it stands stuff breaks horribly. The first error thrown by starting a random PythonCocoa app is in NibClassBuilder, where an NSString is fed to an os.path function. I _think_ for many cases it's enough if we implement all string methods. There aren't even that many: 'capitalize', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'islower', 'isnumeric', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill' It would perhaps be best if the ones that return a string would return Python str or unicode instances and not a new NSString instance. In many cases the implementation could consist of: def a_random_string_method(self): s = convert_to_python_string(self) return s.a_random_string_method() If there is an NSString counterpart, it's perhaps better to do: def a_random_string_method(self): s = self.NSString_equivalent_of_a_random_string_method() return convert_to_python_string(s) Hm, but then again, maybe not. Thoughts? The buffer interface should make raw NSStrings work in many cases (eg. system calls), yet I don't think it's possible to make it work for unicode strings in all cases: we would need to provide a raw character buffer that's compatible with the unicode internals. We need to figure that out. [I just looked at the implementation of the "et" format for PyArg_ParseTuple() (gets a buffer with a specified encoding), and while traversing down the call graph I came across PyUnicode_FromObject(). This call wants a buffer, which sucks for our purposes. However, a comment in that function says /* XXX Perhaps we should make this API an alias of PyObject_Unicode() instead ?! */ which might be exactly what we need, as _that_ one actually calls ob.__unicode__(). So by careful lobbying me might be able to fix this for Python 2.3. Must hurry, though, as 2.3a2 is supposed to be out soon. Code to be compatible with 2.2 would then still have to call unicode(anNSString).] Oh, it's that time again: Must Sleep... Just |
From: <bb...@ma...> - 2003-02-05 01:24:00
|
On Tuesday, Feb 4, 2003, at 18:28 US/Eastern, Just van Rossum wrote: >> It is unreasonable to expect that the internal implementation will >> remain consistent over time, yet that is exactly what a partial >> conversion solution expects. > > Ok, I'm about to give in. Can we table this for a bit? I'm in the middle of an implementation that *may* actually solve this problem in a somewhat graceful fashion that makes both of us happy. I'm not sure and it'll take more time for me to figure out how to explain it than to do some more research programming to determine if it'll work. That, and I'm tired of tossing a bunch of words out there without backing it with useful examples/code.... and I'm tired of having time sucked from forward progress for the sake of a [very interesting] argument. I'm sure that there are a lot of others on this list-- yourself at the head of the list-- in the same boat. BTW: I do have Python->ObjC working nicely -- Python strings pop into ObjC world without copying data. b.bum |
From: <bb...@ma...> - 2003-02-05 16:55:57
|
On Tuesday, Feb 4, 2003, at 18:28 US/Eastern, Just van Rossum wrote: > Let's focus on making NSString instances work as much as Python strings > as possible. > > For fun, I removed the conversion, and (quite obviously) as it stands > stuff breaks horribly. The first error thrown by starting a random > PythonCocoa app is in NibClassBuilder, where an NSString is fed to an > os.path function. I _think_ for many cases it's enough if we implement > all string methods. There aren't even that many: > > 'capitalize', 'center', 'count', 'encode', 'endswith', > 'expandtabs', > 'find', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', > 'islower', 'isnumeric', 'isspace', 'istitle', 'isupper', 'join', > 'ljust', 'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', > 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', > 'title', 'translate', 'upper', 'zfill' In objc_support.m, I changed the thing that converts from NSString to PythonStrings to this: else if ([obj isKindOfClass:[NSString class]]) { retobject = buffer_from_nsstring(obj); } It is really just a convenience hook via which I can try different recipes for converting between. I current implement buffer_from_nsstring() as: static PyObject* buffer_from_nsstring(NSString *aString) { PyObject* result; NSData* data = [aString dataUsingEncoding:NSASCIIStringEncoding]; if (data == NULL) { const char* utf8 = [aString UTF8String]; result = PyUnicode_DecodeUTF8(utf8, strlen(utf8), "strict"); } else { result = PyString_FromStringAndSize([data bytes], [data length]); } return result; } This works-- it is basically *exactly* like the implementation in CVS. I tried an implementation that returns a character buffer, but a unit test that does... self.assertEquals("foo", NSString.stringWithString_("foo")) ... fails because "foo" cannot be compared to an instance of <character buffer>. Nuts. What we really need is a way to attach the NSString instance to the PythonString instance such that any crossing of the bridge can directly grab the NSString on entry into ObjC. I have realized that I'm wrong in regards to avoiding conversion -- conversion isn't the problem. The problem is the lack of preserving the identity as a string crosses from Python to ObjC and back again. That the developer will always have to access the NSString methods via unbound methods is annoying, but not catastrophically so. Example: By 'preserving the identity', I mean that the assertion error in the following should not happen [should behave like the Python equivalent]: >>> from Foundation import * >>> a = NSMutableArray.array() >>> s = "foo bar baz" >>> a.addObject_(s) >>> id(s) 1669344 >>> id(a[0]) 6531696 >>> assert(id(s) == id(a[0])) Traceback (most recent call last): File "<stdin>", line 1, in ? AssertionError >>> k = [s] >>> assert(id(s) == id(k[0])) >>> Mutable strings raise other issues -- mainly that we have to deal with them at all. :-) b.bum |
From: Bob I. <bo...@re...> - 2003-02-05 17:12:13
|
On Wednesday, Feb 5, 2003, at 10:23 America/New_York, bb...@ma... wrote: > > What we really need is a way to attach the NSString instance to the > PythonString instance such that any crossing of the bridge can > directly grab the NSString on entry into ObjC. > > I have realized that I'm wrong in regards to avoiding conversion -- > conversion isn't the problem. The problem is the lack of preserving > the identity as a string crosses from Python to ObjC and back again. > That the developer will always have to access the NSString methods via > unbound methods is annoying, but not catastrophically so. > The method I proposed the other day, subclassing str (and converting on first entry from objc->python) and implementing a custom version of __new__ should solve (almost?) all of these problems... with the caveat that it takes more memory because it converts the string (perhaps only the first time across the bridge). It would certainly fill in for a python str in 99% of the places that a python str is accepted (because it's a subclass of str itself). You can also solve the NSString accessibility as well this way with the __getattr__ to the instance of the NSString it keeps around. Of course, you'd still need the ObjC class on the other side to accept Python strings.. which I think already works just fine? -bob |
From: Ronald O. <ous...@ci...> - 2003-02-05 20:13:16
|
I've implemented a scheme that was mentioned on the list a while back during the discusion of posing and which should make experimenting with the various proposed solutions a little easier (mostly for the creation of a Python representation of Objective-C instances, wrapping Python strings using a custom proxy object seems to be rather uncontroversial). Not only that, it also makes the bridge code slightly simpler. What I've done: * All custom proxy-objects (OC_PythonObject and friends) implement __pyobjc_PythonObject__. This method returns a new reference to the wrapped Python object * All Python subclasses of Objective-C classes also implement this method * And last but not least, a category on NSObject also defines this method (both as an instance and as a class method). Both return a proxy for self (the instance of the class). pythonify_c_value, case _C_ID, is now a lot simpler than it was before: It calls __pyobjc_PythonObject__. End of story. This works rather well, and it is quite easy to add support for special treatment for some classes, I've done so for NSString and NSNumber: Just implement a category implementing __pyobjc_PythonObject__ and your done. The __pyobjc_PythonObject__ implementation for NSNumber converts back to the corresponding Python number, which solves the bug in test_nsundomanager (the int->NSNumber problem mentioned by David). The functions in Foundation.Conversions don't like this change (obviously). test_nsnumber also fails, because NSNumber instances are no longer visible from Python. The __pyobjc_PythonObject__ implementation for NSString exactly mirrors the code that is currently in pythonify_c_value. Feel free to experiment with that code :-) BTW. Is anyone using the Objective-C style interface to Python objects as defined by OC_PythonObject (e.g. [pyobject1 numberAdd:pyobject2])? I'd like to remove this interface as most interesting types are, or will be, proxied using classes with a Cocoa-style interface anyway. I'll check these changes in later on this evening (it is evening over here in Europe :-), after cleaning up some issues with other pending changes. Ronald |
From: <bb...@ma...> - 2003-02-05 20:20:59
|
On Wednesday, Feb 5, 2003, at 15:12 US/Eastern, Ronald Oussoren wrote: > BTW. Is anyone using the Objective-C style interface to Python objects > as defined by OC_PythonObject (e.g. [pyobject1 numberAdd:pyobject2])? > I'd like to remove this interface as most interesting types are, or > will be, proxied using classes with a Cocoa-style interface anyway. I don't believe so. Also, OC_PythonString.[hm] was not being used either, but I'm now using it for the String proxy I have put together -- don't bother removing it. It still needs clean up and may need adjusting after your changes are committed. The other changes sound like a grand improvement. b.bum |
From: Lele G. <le...@se...> - 2003-02-05 22:12:03
|
>>>>> On Wed, 5 Feb 2003 21:12:08 +0100, Ronald Oussoren <oussoren@cistro= n.nl> said: Ronald> What I've done: Ronald> pythonify_c_value, case _C_ID, is now a lot simpler than Ronald> it was before: It calls __pyobjc_PythonObject__. End of Ronald> story. Very very nice! I'm sadly short of time to contribute, but I'm astonished seeing all you bringing PyObjC this far! ;-) G'night, ciao, lele. --=20 nickname: Lele Gaifax | Quando vivr=F2 di quello che ho pensato ieri real: Emanuele Gaifas | comincer=F2 ad aver paura di chi mi copia. email: le...@se... | -- Fortunato Depero, 1929. |
From: Mike F. <mi...@lo...> - 2003-02-11 16:49:15
|
I am not entirely clear about what exactly is being discussed here... this message was forwarded to me by Bill. I will make the point (which Bill already undoubtedly knows) that in Cocoa the types declared for arguments and return values in the API are more about what the caller can do with the return value or what the method will do with the argument rather than what the return value really will be or what the argument must be. For example, NSView's -subviews method is declared to return an NSArray. Forever it has actually returned an NSMutableArray: the one it uses to manage its subviews. The fact that it declares the return value is NSArray means that the caller is not allowed to change it, not that it CANNOT be changed. In reverse, NSWindow's -setTitle: takes an NSString. That does not mean I cannot pass it an NSMutableString, it means that under no circumstances will the window alter the string, even if it is mutable. Mike Begin forwarded message: > From: bb...@ma... > Date: Tue Feb 4, 2003 1:37:00 PM US/Pacific > To: pyo...@li..., mf...@lo... > Subject: Re: [Pyobjc-dev] NSString & mutability > > On Tuesday, Feb 4, 2003, at 15:56 US/Eastern, Just van Rossum wrote: >> I'm totally willing to accept a surprise like that. I don't even see >> the >> problem when using such an API from Python: you call >> fooObject.setMyNameIs_() with a Python string, you call myNameIs() and >> get a Python string. Same string, different id. No problem in Python. > > I'm not willing to accept a surprise like that because it will greatly > reduce the value of PyObjC in quite a number of situations. This is > not idle speculation. I have made the same mistake in the past > [creating a bridge that was dependent on internal implementation of > underlying frameworks] and it rendered the bridge [Tcl <-> ObjC, in > this case] nearly useless until it was fixed -- it broke-- or > sometimes didn't break-- depending on what order the user did things > simply because some random bit of code somewhere chose to return > *this* private subclass vs. *that* private subclass as some internal > optimization hack that was *not* apparent, no relevant to, the > advertised API. > > The fundamental problem is that partial conversion relies on the > internal implementation to stay the same over time. The current > behavior does not; it remains consistent. Partial conversion > behavior that is dependent upon the internal implementation of 'third > party' [Apple is a third party, in this case] frameworks will lead to > behavior that changes over time and through factors outside of our > control. > > More below.... > >> Can you please give an example of an _actual_ problem? I'll have a go >> myself: > > Off the top of my head, no-- I can't remember a specific example. But > that is mostly because I have been relying on the APIs as advertised > by the classes and not their internal implementations for long enough > that I haven't had this problem in a while. It *does* come up on the > mailing lists on occasion, but searching for "nsmutablestring nsstring > return" yields an awful lot of noise hits. > >> Let's assume the API does the reverse: it takes an immutable string, >> yet >> returns its internal mutable copy, although myNameIs is declared to >> return an NSString. Now there _is_ a surprise: instead of a 100% >> equivalent string we get an NSMutableString instance. Ok, a surprise, >> but is it so bad? If the object internally uses a mutable string, it's >> likely that this is clear from the nature of the object (eg. it's some >> sort of editor for the string). So I still think such a surprise will >> be >> rare. > > I agree that the situations where this arise will be rare. But, when > they do arise, the results are the absolute worst kinds of bugs in the > world to fix. It breaks on customer A's computer, but not customer > B's -- but they are [supposedly] identical. Oh, wait a minute, > Customer B upgraded to version 1.234b of the some random plugin while > customer A is still using 1.233. > > Another exmaple: What if Mike [who I included in this because he may > have some useful input-- sorry, Mike :-] changes the implementation of > TextExtras and throws an NSMutableString into some random object > collection that ends up on the other side of the bridge at some point? > The Python developer is screwed if there code breaks. > > What happens when Apple ships the 10.2.5 update and they change some > random bit of internal implementation such that a method that used to > return (NSMutableString*) now *always* returns (NSString*)? Assuming > the PyObjC developer can figure out what is going on, are they now > supposed to write OS X version specific code at the x.x.1 level? > > Now-- what about the developers that will be using PyObjC with > multiple thousands of lines of code embedded in random frameworks > across some large scale system? For them, the choice of using PyObjC > now comes with the cost of having to ensure that every method that > *may* return an NSMutableString* when it is declared with an NSString* > return value is identified and compensated for. This is not a > contrived example-- I and a number of people I have been in contact > with since PyObjC became a visible project again-- have used PyObjC in > this context in the past and are planning on doing so in the future > [some already are]. This would be a deal killer for them. > > Bottom line: PyObjC -- just like the AppleScript in an AS Studio > project or a good chunk of the ObjC in a pure ObjC Cocoa app -- is the > glue that holds together all of the random objects in a fashion that > solves whatever problem the developer is trying to address. The > developer does not have full and complete control over those objects-- > heck, there may be entire chunks of implementation present that their > code has no awareness of whatsoever [TextExtras]. For such a system > to work, the objects must be glued together as advertised by the APIs. > To do otherwise will render a system that is fragile. Worse, it > will create a system whose fragility is dependent upon unreasonable > expectations. > > It is reasonable to expect-- and history indicates it is true-- that > the behavior of the NSCell API will remain consistent going forward. > It is unreasonable to expect that the internal implementation will > remain consistent over time, yet that is exactly what a partial > conversion solution expects. > > b.bum > |
From: Ronald O. <ous...@ci...> - 2003-02-05 08:40:48
|
On Tuesday, Feb 4, 2003, at 21:56 Europe/Amsterdam, Just van Rossum wrote: > bb...@ma... wrote: > >> Nice hack, but.... >> >> What about all the code that might return a mutable string depending >> on how the developer exercises the API? Are you willing to assume >> that every getter and setter that internally makes a immutable copy >> of the set string value? i.e. that... >> >> .... [fooObject setMyNameIs: someRandomMutableString]; return >> [fooObject myNameIs] .... >> >> .... that -myNameIs will return an immutable string? > > I'm totally willing to accept a surprise like that. I don't even see > the > problem when using such an API from Python: you call > fooObject.setMyNameIs_() with a Python string, you call myNameIs() and > get a Python string. Same string, different id. No problem in Python. > > Can you please give an example of an _actual_ problem? I'll have a go > myself: > > Let's assume the API does the reverse: it takes an immutable string, > yet > returns its internal mutable copy, although myNameIs is declared to > return an NSString. Now there _is_ a surprise: instead of a 100% > equivalent string we get an NSMutableString instance. Ok, a surprise, > but is it so bad? If the object internally uses a mutable string, it's > likely that this is clear from the nature of the object (eg. it's some > sort of editor for the string). So I still think such a surprise will > be > rare. The 'scary' part is that the behavious could change without notice from one update of MacOS to the other, because NSMutableString is a subclass of NSString switching from a returnvalue of type NSString to one of NSMutableString is a backward compatible change. > >> See this message -- it is still quite relevant. Mike Ferris is one >> of the guys who helped write the AppKit and Project Builder. >> >> http://www.omnigroup.com/mailman/archive/macosx-dev/2000-May/001886. >> html > > It's an example of NSArray, which we don't convert, so we live > dangerously anyway in PyObjC as we don't even have the hint from the > header that we _shouldn't_ mutate even if it is mutable. I think you should read this as 'even though some methods are defined as returning an NSFoo they may return any subclass (like NSMutableFoo), depending on the actuall type is bad'. Read like that this is pretty relevant to our discussion: If we convert NSString and wrap NSMutableString (a subclass of NSString) the user may sometimes get a python string object and sometimes not from functions/methods that are documented as returning a NSString. Unless we can make sure that the NSMutableString wrapper is usable everywhere where a Python string is this will give us great headaches in the future. Ronald |
From: David E. <epp...@ic...> - 2003-02-05 17:05:58
|
On 2/5/03 9:39 AM +0100 Ronald Oussoren <ous...@ci...> wrote: > I think you should read this as 'even though some methods are defined as > returning an NSFoo they may return any subclass (like NSMutableFoo), > depending on the actuall type is bad'. Read like that this is pretty > relevant to our discussion: If we convert NSString and wrap > NSMutableString (a subclass of NSString) the user may sometimes get a > python string object and sometimes not from functions/methods that are > documented as returning a NSString. The bad part about this is that the mutable returns may be quite rare, so you won't notice for a long time that your code has a bug. I'd rather find out quickly when a str() wrapper is necessary. -- David Eppstein UC Irvine Dept. of Information & Computer Science epp...@ic... http://www.ics.uci.edu/~eppstein/ |
From: Just v. R. <ju...@le...> - 2003-02-04 20:42:53
|
Just van Rossum wrote: > However, str() fails: > > >>> str(x) > Traceback (most recent call last): > File "<stdin>", line 1, in ? > TypeError: __str__ returned non-string (type NSCFString) > >>> > > I can't seem to find where I can repair this. Ok, I understand why it happens: __str__ returns [obj description], and when we convert _all_ strings, this automatically works correctly, but if we don't it doesn't <wink>, since it seems any NSString just returns self from description. But now I don't know how to work around that... Any hints? (Btw. I've found Lib/objc/_convenience.py.) Just |
From: Just v. R. <ju...@le...> - 2003-02-04 22:03:46
Attachments:
partialstringconversion.patch
|
Just van Rossum wrote: > Ok, I understand why it happens: __str__ returns [obj description], > and when we convert _all_ strings, this automatically works > correctly, but if we don't it doesn't <wink>, since it seems any > NSString just returns self from description. But now I don't know how > to work around that... Any hints? (Btw. I've found > Lib/objc/_convenience.py.) I've managed to "fix" this. I've attached a patch that more or less completely implements partial conversion. unicode(someMutableString) works as expected (as well as str()). And now I'm going to read Bill's epos a second time ;-) Just |