pyobjc-dev Mailing List for PyObjC (Page 295)
Brought to you by:
ronaldoussoren
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(9) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(1) |
Feb
(2) |
Mar
(3) |
Apr
(30) |
May
(18) |
Jun
|
Jul
(4) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2002 |
Jan
(7) |
Feb
(2) |
Mar
(1) |
Apr
|
May
|
Jun
(3) |
Jul
(13) |
Aug
|
Sep
(23) |
Oct
(180) |
Nov
(291) |
Dec
(95) |
2003 |
Jan
(338) |
Feb
(352) |
Mar
(97) |
Apr
(46) |
May
(226) |
Jun
(184) |
Jul
(145) |
Aug
(141) |
Sep
(69) |
Oct
(161) |
Nov
(96) |
Dec
(90) |
2004 |
Jan
(66) |
Feb
(87) |
Mar
(98) |
Apr
(132) |
May
(115) |
Jun
(68) |
Jul
(150) |
Aug
(92) |
Sep
(59) |
Oct
(52) |
Nov
(17) |
Dec
(75) |
2005 |
Jan
(84) |
Feb
(191) |
Mar
(133) |
Apr
(114) |
May
(158) |
Jun
(185) |
Jul
(62) |
Aug
(28) |
Sep
(36) |
Oct
(88) |
Nov
(65) |
Dec
(43) |
2006 |
Jan
(85) |
Feb
(62) |
Mar
(92) |
Apr
(75) |
May
(68) |
Jun
(101) |
Jul
(73) |
Aug
(37) |
Sep
(91) |
Oct
(65) |
Nov
(30) |
Dec
(39) |
2007 |
Jan
(24) |
Feb
(28) |
Mar
(10) |
Apr
(2) |
May
(18) |
Jun
(16) |
Jul
(21) |
Aug
(6) |
Sep
(30) |
Oct
(31) |
Nov
(153) |
Dec
(31) |
2008 |
Jan
(63) |
Feb
(70) |
Mar
(47) |
Apr
(24) |
May
(59) |
Jun
(22) |
Jul
(12) |
Aug
(7) |
Sep
(14) |
Oct
(26) |
Nov
(5) |
Dec
(5) |
2009 |
Jan
(10) |
Feb
(41) |
Mar
(70) |
Apr
(88) |
May
(49) |
Jun
(62) |
Jul
(34) |
Aug
(15) |
Sep
(55) |
Oct
(40) |
Nov
(67) |
Dec
(21) |
2010 |
Jan
(60) |
Feb
(17) |
Mar
(26) |
Apr
(26) |
May
(29) |
Jun
(4) |
Jul
(21) |
Aug
(21) |
Sep
(10) |
Oct
(12) |
Nov
(3) |
Dec
(19) |
2011 |
Jan
(3) |
Feb
(13) |
Mar
(8) |
Apr
(8) |
May
(17) |
Jun
(20) |
Jul
(21) |
Aug
(7) |
Sep
|
Oct
|
Nov
(9) |
Dec
(11) |
2012 |
Jan
(3) |
Feb
|
Mar
|
Apr
(5) |
May
(4) |
Jun
(14) |
Jul
(5) |
Aug
(2) |
Sep
(15) |
Oct
(2) |
Nov
(23) |
Dec
(1) |
2013 |
Jan
(8) |
Feb
(1) |
Mar
|
Apr
|
May
(5) |
Jun
(1) |
Jul
(5) |
Aug
(4) |
Sep
|
Oct
(12) |
Nov
(10) |
Dec
(3) |
2014 |
Jan
(7) |
Feb
(14) |
Mar
(2) |
Apr
|
May
(2) |
Jun
(11) |
Jul
(10) |
Aug
(4) |
Sep
|
Oct
(8) |
Nov
(1) |
Dec
(2) |
2015 |
Jan
(9) |
Feb
(7) |
Mar
(1) |
Apr
|
May
(7) |
Jun
|
Jul
(5) |
Aug
(6) |
Sep
|
Oct
(1) |
Nov
(4) |
Dec
|
2016 |
Jan
(1) |
Feb
(1) |
Mar
(4) |
Apr
(2) |
May
(1) |
Jun
|
Jul
(6) |
Aug
(8) |
Sep
(21) |
Oct
(17) |
Nov
|
Dec
(36) |
2017 |
Jan
(6) |
Feb
(2) |
Mar
(4) |
Apr
(2) |
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
(6) |
2018 |
Jan
(2) |
Feb
(3) |
Mar
(3) |
Apr
(14) |
May
(2) |
Jun
(2) |
Jul
(4) |
Aug
(3) |
Sep
(6) |
Oct
(16) |
Nov
(1) |
Dec
(6) |
2019 |
Jan
(3) |
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
(6) |
Nov
|
Dec
|
2020 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(2) |
Jun
(1) |
Jul
(7) |
Aug
(1) |
Sep
(1) |
Oct
|
Nov
(2) |
Dec
(1) |
2021 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
(5) |
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2023 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
|
Dec
|
2025 |
Jan
(2) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Jack J. <Jac...@or...> - 2002-10-29 21:17:55
|
On dinsdag, oktober 29, 2002, at 02:06 , Bill Bumgarner wrote: >> To answer my own question: no, it doesn't. isMultiThreaded >> still returns NO after this call. >> Is this a problem? If so, is there a way to tell NSThread that >> we *are* multithreaded? > > That would seem to be a bug that should be reported to > bugreport.apple.com. If you have a little hunk of test code, > that typically accelerates Apple's bug fixing process > considerably. I'll try and find the time, but feel free to beat me to it:-) > > It sounds like you'll need to create a zero resources thread > via NSThread: > > [NSThread detachNewThreadSelector:@selector(intoTheVoid:) > toTarget:[NSObject class] withObject: nil]; > > @implementation NSObject (TheVoid) > + (void) intoTheVoid: aNothing > { > l = [[NSLock alloc] init]; > [l lock]; > [l lock]; > } > @end I did this (but of course with a bit of code a lot less elegant than yours:-), and it solves the isMultiThreaded problem. Unfortunately it doesn't solve my PyOpenGL problem, but that's a different story... Something else you may want to try though, if this is needed for PyObjC, is to let the thread terminate. The comments in NSThread.h lead me to believe that once you've made the transition to a multithreaded program there's no going back. If that's indeed the case then letting the thread terminate isn't a problem. -- - 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: <bb...@ma...> - 2002-10-29 16:16:27
|
Thank you! That would be brilliant -- we can drop it in the Docs directory. At some point, I really want to pull out the web site and stick it in CVS. It would be doubly-brilliant if we could compile the web site and the shipped-with-the-module docs from the same tree of source [Fink does this -- and Fink compiles the content down to HTML, text, and-- I believe-- some other formats all from the same source]. But-- a "getting started writing Cocoa Python" apps would be a HUGE step forward from where we are today! If you want to have a crack at some new content for http://pyobjc.sourceforge.net/, please feel free! b.bum On Tuesday, October 29, 2002, at 11:10 AM, Steven D. Arnold wrote: > On 10/29/02 8:19 AM, "bb...@ma..." <bb...@ma...> wrote: > >> This is extremely valuable feedback -- every question helps us to >> understand where we need to provide better documentation or better >> examples. > > Your message gave me everything I needed -- HelloWorld works! > > As thanks for the help, I'll write a guide to creating a Cocoa app in > Python, using HelloWorld as an example. I guess I'll put it in HTML > format > to best support graphics and avoid proprietary formats. I'll > contribute it > to the project under your license terms. I should have a rough draft > in a > week or so. If you want any of the above to be different, e.g. text > format > instead of HTML, let me know ASAP. > > Thanks again! > > steve > -- > > > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev > b.bum I ride tandem with the random.... .... things don't run the way I planned them. |
From: Steven D. A. <st...@ne...> - 2002-10-29 16:10:14
|
On 10/29/02 8:19 AM, "bb...@ma..." <bb...@ma...> wrote: > This is extremely valuable feedback -- every question helps us to > understand where we need to provide better documentation or better > examples. Your message gave me everything I needed -- HelloWorld works! As thanks for the help, I'll write a guide to creating a Cocoa app in Python, using HelloWorld as an example. I guess I'll put it in HTML format to best support graphics and avoid proprietary formats. I'll contribute it to the project under your license terms. I should have a rough draft in a week or so. If you want any of the above to be different, e.g. text format instead of HTML, let me know ASAP. Thanks again! steve -- |
From: <bb...@ma...> - 2002-10-29 13:19:47
|
On Tuesday, October 29, 2002, at 01:42 AM, Steven D. Arnold wrote: > I appreciate the helpful answers I've gotten so far from Ronald and > Bill. I > hate to ask so many questions, but I think I'm very close to a working > Python/Cocoa application. This is extremely valuable feedback -- every question helps us to understand where we need to provide better documentation or better examples. > I've done as I said in a previous post: > > 1. Start PB, create Cocoa app > 2. Open resources, double-click the IB icon > 3. Create a subclass of NSObject, in my case HelloWorld > 4. Create an outlet called "text" which is the NSTextField intended to > display the "Hello World" message > 5. Create an action called "sayIt" which is wired to a button on the > form > 6. Modify main.m to look exactly as described in Ronald's TableModel2 > project > 7. Create a file Main.py which is in the "Other Sources" in my project. > This file looks like this: > > import sys > import os.path > > sys.path.insert( 0, os.path.join( sys.path[ 0 ], "pyobjc" ) ) > > import objc > import Foundation > import AppKit > print "foo" > > class HelloWorld(Foundation.NSObject): > __slots__ = ( 'text' ) For an outlet, replace the above line with this: text = objc.IBOutlet('text') I wonder if there is a way to remove this requirement? I'll have to investigate the whole IBConnection stuff -- I just did a boat load of custom IB work (converting NIB files from NS 3.3 -> OS X) and the APIs are still fresh. > def __init__( self ): > print "hello!" > self.text.setStringValue_( "Hello World!" ) This should just be init() and it should return self. However... For initialization from a NIB file, implement awakeFromNib() -- there are cases where the object might be instantiated before the NIB is loaded (NIB loading takes a significant hunk of time -- lazy loading the NIB for a piece of UI that the user may not use can increase perceived performance). From the currency example: def awakeFromNib(self): print "awakeFromNib" # Provide some defaults for the user... self.dollarField.setFloatValue_(2.0) self.rateField.setFloatValue_(3.0) > def sayIt( self ): > self.text.setStringValue_( "Hello World, I am here!" ) An action method takes a single argument, the sender of the action. So, this should be: def sayIt_( self, sender ): self.text.setStringValue_( "Hello World, I am here!" ) b.bum |
From: Bill B. <bb...@co...> - 2002-10-29 13:07:13
|
On Tuesday, October 29, 2002, at 07:16 AM, Jack Jansen wrote: > On Tuesday, Oct 29, 2002, at 11:31 Europe/Amsterdam, Jack Jansen wrote: >> On Monday, Oct 28, 2002, at 17:45 Europe/Amsterdam, Bill Bumgarner >> wrote: >>> When traversing from Python into Obj-C in a thread that was created >>> in pure python (i.e. is just a pthread, does not have an NSThread >>> instance), invoking NSThread's +currentThread method will return an >>> NSThread that encapsulates the already created pthread. >> >> If you do this, does that make a pthread a fullblown NSThread? I.e. >> does it make the problems you sketched earlier (such as >> isMultiThreaded returning NO) go away? > > To answer my own question: no, it doesn't. isMultiThreaded still > returns NO after this call. > Is this a problem? If so, is there a way to tell NSThread that we > *are* multithreaded? That would seem to be a bug that should be reported to bugreport.apple.com. If you have a little hunk of test code, that typically accelerates Apple's bug fixing process considerably. It sounds like you'll need to create a zero resources thread via NSThread: [NSThread detachNewThreadSelector:@selector(intoTheVoid:) toTarget:[NSObject class] withObject: nil]; @implementation NSObject (TheVoid) + (void) intoTheVoid: aNothing { l = [[NSLock alloc] init]; [l lock]; [l lock]; } @end This will effectively dead lock the thread in a fashion that should use zero CPU cycles (assuming NSLock is correctly implemented). There is also no way to kill the thread -- export the NSLock and call [l unlock] once to do so. Bogus. Totally Bogus. But should do the trick. It is likely that we will need some similar bogosity in the PyObjC bridge. b.bum |
From: Jack J. <Jac...@cw...> - 2002-10-29 12:16:35
|
On Tuesday, Oct 29, 2002, at 11:31 Europe/Amsterdam, Jack Jansen wrote: > > On Monday, Oct 28, 2002, at 17:45 Europe/Amsterdam, Bill Bumgarner > wrote: >> When traversing from Python into Obj-C in a thread that was created >> in pure python (i.e. is just a pthread, does not have an NSThread >> instance), invoking NSThread's +currentThread method will return an >> NSThread that encapsulates the already created pthread. > > If you do this, does that make a pthread a fullblown NSThread? I.e. > does it make the problems you sketched earlier (such as > isMultiThreaded returning NO) go away? To answer my own question: no, it doesn't. isMultiThreaded still returns NO after this call. Is this a problem? If so, is there a way to tell NSThread that we *are* multithreaded? -- - 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...@cw...> - 2002-10-29 10:51:09
|
On Monday, Oct 28, 2002, at 17:45 Europe/Amsterdam, Bill Bumgarner wrote: > When traversing from Python into Obj-C in a thread that was created in > pure python (i.e. is just a pthread, does not have an NSThread > instance), invoking NSThread's +currentThread method will return an > NSThread that encapsulates the already created pthread. If you do this, does that make a pthread a fullblown NSThread? I.e. does it make the problems you sketched earlier (such as isMultiThreaded returning NO) go away? Hmm, this may well point to a solution to a completely different problem I have (my multithreaded OpenGL programs stopped working as of 10.2).... Is there an easy way to do this from C? > I would assume that threaded python already has the pthread > initialized with the appropriate state and it would just be a matter > of adding any bridge specific state at this point? Yes. -- - 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: Steven D. A. <st...@ne...> - 2002-10-29 06:42:55
|
I appreciate the helpful answers I've gotten so far from Ronald and Bill. I hate to ask so many questions, but I think I'm very close to a working Python/Cocoa application. I've done as I said in a previous post: 1. Start PB, create Cocoa app 2. Open resources, double-click the IB icon 3. Create a subclass of NSObject, in my case HelloWorld 4. Create an outlet called "text" which is the NSTextField intended to display the "Hello World" message 5. Create an action called "sayIt" which is wired to a button on the form 6. Modify main.m to look exactly as described in Ronald's TableModel2 project 7. Create a file Main.py which is in the "Other Sources" in my project. This file looks like this: import sys import os.path sys.path.insert( 0, os.path.join( sys.path[ 0 ], "pyobjc" ) ) import objc import Foundation import AppKit print "foo" class HelloWorld(Foundation.NSObject): __slots__ = ( 'text' ) def __init__( self ): print "hello!" self.text.setStringValue_( "Hello World!" ) def sayIt( self ): self.text.setStringValue_( "Hello World, I am here!" ) sys.exit( AppKit.NSApplicationMain(sys.argv) ) 8. Build the project; if the project was called HelloWorld, you'll have a program called HelloWorld.app. When I build and run the program, the window comes up with the form elements I put in place. I can click the button (which is supposed to make an NSTextField say "hello world"), but nothing happens. In the run window of Project Builder, I see the following messages: foo 2002-10-29 01:36:19.450 pysample[784] Could not connect the action sayIt: to target of class HelloWorld 2002-10-29 01:36:19.672 pysample[784] Can't open input server /Library/InputManagers/Menu Extra Enabler Note that it printed the "foo" that I put in my program, above! However, the "hello" that I print in __init__ never gets displayed. So apparently my file is being processed by no instance of HelloWorld is ever being created -- which may explain why it couldn't connect sayIt to my class. So my question is why am I getting the results I'm getting instead of a correct connection to the sayIt method? steve -- |
From: Bill B. <bb...@co...> - 2002-10-28 16:45:50
|
On Monday, October 28, 2002, at 04:00 AM, Ronald Oussoren wrote: > All, > > I just remembered one implementation issue that should be worked on > before reaching a 1.0 release: Thread safety. Agreed. > The current code is probably save for multi-threading, but I haven't > really checked this. Basicly I removed all static/global buffers while > working on the code. > > There are some more issues: > 1. Python has a global interpreter lock. When one thread owns this > lock, no > other thread can execute python code. The bridge currently never > gives up > the GIL when moving into native code and we probably should. I have > not yet > researched what we should do with callbacks from Objective-C to > Python. > > E.g. the NSApplicationMain wrapper should release the GIL before > calling > the actuall function, but how do you regain the GIL during calls to > methods > implemented in Python? > > This is necessary to avoid unecessary blockage of Python threads > during > calls to Objective-C code. I believe Jack covered this, but wanted to add a couple of Obj-C and NS* specific bits of information: As of OS X, NSThreads are actually built on top of pthreads and it should be possible to use Jack's code directly. From the documentation: ... NSThreads are built upon POSIX threads (pthreads). You can create your own pthreads, but some Cocoa classes, such as NSAutoreleasePool, expect to be running within an NSThread and may not work properly in a pthread. Creating a pthread does not notify Cocoa classes that the application has become multithreaded, so the NSThread method isMultiThreaded may return NO. If you need access to the pthread within an NSThread, call the pthread_self function from within that thread. ... I would still recommend using the NSThread based API to create threads if the goal is to multi-thread an app that mixes Python and Obj-C in threads (for an app that uses pure-python in the threads, there is no need) because this is the only way that the ObjC runtime is going to become "thread aware". Specifically, see the documentation on these notifications: FOUNDATION_EXPORT NSString * const NSWillBecomeMultiThreadedNotification; FOUNDATION_EXPORT NSString * const NSDidBecomeSingleThreadedNotification; FOUNDATION_EXPORT NSString * const NSThreadWillExitNotification; However, once the NSThread is created, the pthreads API can be used to store state and otherwise manipulate the thread -- the NSThread API is just the glue to make sure the ObjC runtime has the opportunity to deal w/the appropriate notifications. If desired, NSThread provides for storage of per-thread state in a mutable dictionary. Simply invoke -threadDictionary while executing in the thread that wants to store/retrieve the state. When traversing from Python into Obj-C in a thread that was created in pure python (i.e. is just a pthread, does not have an NSThread instance), invoking NSThread's +currentThread method will return an NSThread that encapsulates the already created pthread. I would assume that threaded python already has the pthread initialized with the appropriate state and it would just be a matter of adding any bridge specific state at this point? It sounds like the harder problem is when the developer crosses from ObjC -> Python in a thread that was not created in Python and, therefore, the interpreter has not initialized the pthread state in the specific context of Python? Note that as of 10.2, NSThread offers these two *extremely* handy methods: - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; b.bum |
From: <bb...@ma...> - 2002-10-28 15:55:03
|
On Monday, October 28, 2002, at 03:51 AM, Ronald Oussoren wrote: > Jonathan, > > I agree that we should try to abstract away manual management of > reference counts. Until a few days ago I believed we already reached > this point. Even without the automatic compensation for the methods that transfer ownership, we have abstracted away the manual management of reference counts in almost all cases. The remaining issues are not specific to Obj-C, they are specific to particular kits of objects implemented in using Objective-C. Therein lies the problem-- every developer who builds a kit of objects can choose [consciously or not, doesn't matter] to implement a completely different retain/release/autorelease pattern across their API. Example: I often use the +new pattern to return an object with ownership transfer implied. I.e. +newWithFile: (NSString *) aPath; returns a freshly instantiated instance of my Image class that has been retained. However, Apple's DragNDropOutlineView example uses +newGroupFromLeaf: to return an autoreleased object. We cannot possibly predict what developers are going to do with the bridge. Nor can we ever completely hide the retain/release/autorelease "feature" of Objective-C. It is very much a reality and will always be a reality in any bridged environment. However, what we can do is make the bridge work as transparently as possible in light of this reality (which it pretty much already does)! In particular, we can make sure that if a program fails because of a retain/release/autorelease problem, it does so in as graceful of a fashion as possible (i.e. it dies in ObjC, not python, as often as possible :-). To these ends, let's do a reality check on the problem. The problem is not that we need to deal with -retain/-release in the normal course of using the bridge -- that is already very cleanly taken care of. The problem is that there are a handful of methods-- +alloc, +copy, +mutableCopy, +new, and any of a number of methods that the developer might create that we cannot know about in advance-- that "transfer ownership" to the caller. That is, they return retained objects. In the context of the bridge, this yields an extra reference count and Ronald's goal is to try and automatically compensate for that reference count. A worthy goal, but not one that can be achieved with 100% coverage. OK-- so why not just leave it out? What are the implications then? To the ObjC developer, the apps "just work" as expected. To the Python developer, the apps "just work" as expected, but leak a little bit of memory. Leaks are a hell of a lot easier to fix than retain/release/autorelease crashes. Furthermore, it means that taking advantage of a new framework/bundle of objects is as easy simply dynamically loading the code -- no need to worry about analyzing the API and trying to figure out what methods should be "special cased" before we can even write line-one of python code against that API. I have worked on a number of language bridges -- Java<->ObjC, Perl<->ObjC (long before CamlBones), Tcl<->ObjC, Tcl<->Python [don't ask], and a couple that involved bridging languages I created to Python or Obj-C -- and in *every single case*, a decision to special case as would be [is] required by this [relatively small] problem was a *very bad idea*. It caused confusion in the developer community-- including confusion among the authors of the bridge-- and was a constant source of maintenance and support headaches. > There are now two sets of ... There will always be situations that expose retain/release in contexts that do not map directly to a pattern we have quantified. An example: when implementing a window controller, it is not uncommon to do a [self retain] when the NIB is loaded (or the window is displayed) and a [self autorelease] in windowWillClose:. That is, the window controller implements a "as long as my window is open-- miniaturized or not, doesn't matter-- I should remain in existence" notion. This pattern makes it extremely easy to implement multi-document apps where the application doesn't manage the list of documents in some formal "ownership implied" fashion. (This is the paradigm that the Web Services Tool follows, btw). > 1. Bill mentioned that it is common in some Objective-C code to > transfer > ownership of returned objects to the caller (He's the resident > expert > on these issues, I'm learning Objective-C/Cocoa as a go along). > > It will be hard to correctly identify all these cases. IMHO this > shouldn't > keep us from doing away with autorelease/release/retain in Python > code: > it will just be a little harder to correctly wrap an Objective-C > class > library. As wrapping an Objective-C class is an order of magnitude > simpler > than wrapper other 'native' code that should not be a problem. I suppose that this basically introduces a wrapping step into the "let's use some random hunk of dynamically loadable API" process? If that step is not taken, then the retains will not be compensated for in the bridge? I.e. the step is optional. As long as the wrapping step is optional, it isn't a big deal. If it becomes non-optional, then it vastly increases the complexity of using external frameworks/bundles over what we have today (a one liner to load the bundle/framework w/some optional glue code that Ronald has nicely documented in the wrapping.txt document). > 2. Bill also mentioned a coding style that uses 'autorelease' to make > sure > that an object is around to the end of the current loop through the > eventloop (which in case of non-GUI programs may be quite a long > time). > > I don't really like this coding style, so IMHO it is not a problem > to use > 'obj.retain().autorelease()' in these cases, instead of just > 'obj.autorelease()'. I'm also pretty sure that doesn't really have > anything > to do with the automatic management of refcounts by the bridge. The end result would be that the retain/autorelease is still exposed to the Python developer while the ObjC developer has to remember a special case.... I would rather the solution that exposes only the autorelease to the python developer and leaves things as is for the ObjC developer. The reality in this situation is that to use this pattern requires knowledge of the ObjC patterns of object management and the various APIs (most likely NSTimer or NSNotification) therein. Keep in mind that an autorelease pool's lifespan may not be tied to one pass through a run loop and, therefore, object's like NSTimer-- which are processed as a part of passing through the run loop-- are perfectly valid in this context. We cannot possible predict what the developer is going to do... > 3. The NSMutableArray class cluster (and probably all > NS<DataStructure> class > clusters) play games with reference counts during allocation. This > is not > a problem if you use the common Objective-C idiom, but it is when > you try > to automate management of reference counts. > > Basicly the issue is that the Objective-C manual strongly suggest > that the > following two lines should be equivalent, but they are not for > these class > clusters: > > NSArray.alloc().autorelease().init() # Basicly what the bridge does > NSArray.alloc().init().autorelease() # Common Objective-C idiom > > I'm thinking on how to fix this. The one requireing the least > amount of > engeneering is saying "Don't use 'alloc().init()' for these class > clusters", > or even "Don't allocate Objective-C containers from Python". I > don't really > like this and am thinking on how to fix this in a correct manner. If we create a special case to handle this situation, it will only cause maintenance hell down the road. What if Apple changes the semantics? What if new collection classes are introduced that suddenly start breaking in the way NSArray does now? What if a third party creates collection classes with the same behavior as Apple's? b.bum |
From: <bb...@ma...> - 2002-10-28 15:42:16
|
First, I would like to say THANK YOU!!!! to Jonathan LaCour for jumping into the discussion. The input is very definitely appreciated. First, what we are really talking about is a relatively small part of the overall problem. That the bridge already automatically increases and decreases the retain count as python references to the ObjC objects are created and destroyed solves most of the problem. The remaining problem is how to deal with the situations that require special casing on a per method basis. On Monday, October 28, 2002, at 12:35 AM, Jonathan LaCour wrote: > I have been watching the discussion on retain/release/autorelease > semantics for a few days and I have put some thought into things. > After a lot of thought, I would like to sincerely urge you to make an > attempt at abstracting out any and all retain/release/autorelease > responsibilities for the programmer. I understand the argument that > it isn't very "Cocoa-like", but I feel that I have a compelling > argument here. I think all of us agree wholeheartedly that eliminating as much of the retain/release/autorelease noise from the Python side of the bridge as is possible is a high priority goal. > First, I believe that you alienate most python programmers by > enforcing memory management on them. Python programmers use python > *because* they don't have to worry about this kind of thing. Its not > that they don't know how or are afraid of it, they just don't want to > touch it. If you force people into it, they will likely end up using > wxPython or something like REALBasic. Agreed. Keep in mind that we are not writing the Foundation, AppKit and the rest of the ObjC APIs in Python -- we are bridging them. While a bridge makes the functionality available on the other side of the bridge, there is always going to be evidence that the functionality on the other side of the bridge is implemented in a different technology. > Secondly, to counter the "Cocoa-like" argument, placing memory > management functionality into a python product is simply not > "Python-like". Sure, it will feel more like developing with Cocoa and > Objective-C, but people are going to use the Python bridge because > they don't want to work with Objective-C when they don't have to. You > have to make a choice here... if PyObjC is for Cocoa developers who > don't know python, then certainly you should try and be "Cocoa-like." > But if PyObjC is for *python programmers* (which I have a feeling it > is), then it should strive to be Python like... meaning no > retain/release at all! Reality: If a developer is using the Objective-C bridge to write an application, they are developing in a combination of Python and Objective-C -- ObjC is still very much a part of the equation. The developer is going to have to know *some* objective-c to get the job done. The current bridge already changes the memory management semantics significantly -- it already obviates the need for calls to -retain/-release/-autorelease when making assignments (foo = bar), when dealing with set membership (-retaining an object before removing it from a set, if that object is to be returned), and when returning objects from methods. These are the most common situations for use of the memory management methods in ObjC. > Memory management through old-style reference counting stands directly > opposite to this power. If you lose this, why use Python at all? You > might as well just use Objective-C (it only takes a few minutes to > learn) and is faster than python. Because python provides much better rapid turnaround than Obj-C ever could.... my compilation time drops to near nothing and I can eliminate 100s of lines of code that would be required in ObjC to do the same thing. That, and I can take advantage of the incredible array of python modules that are available. Example: I can now use the berkeley db as a persistent store from my Obj-C apps with only a handful of lines of code. > When this project came along I was extremely excited about the > possibilities that it offered. Please consider at least making an > automated system an OPTION. I know its hard, but I think that in the > long run it will be worth it. A system like Cocoa without manual > memory management using a language like Python and Mac OS X's > developer tools is such a powerful concept and could truly be the > "killer app" of development on Mac OS X. It can't be an option -- if it is used in one hunk of code and not in another, those two hunks are incompatible. I.e. if I create a framework that contains Python that doesn't use the option and your app uses the option, you can't use my framework. Even without the option, the bridge as it stands today provides the features that you speak... more on that in the next message. b.bum b.bum Are you laughing? ... they are. |
From: Jack J. <Jac...@cw...> - 2002-10-28 09:56:14
|
On Monday, Oct 28, 2002, at 10:00 Europe/Amsterdam, Ronald Oussoren wrote: > All, > > I just remembered one implementation issue that should be worked on > before reaching a 1.0 release: Thread safety. > > The current code is probably save for multi-threading, but I haven't > really checked this. Basicly I removed all static/global buffers while > working on the code. > > There are some more issues: > 1. Python has a global interpreter lock. When one thread owns this > lock, no > other thread can execute python code. The bridge currently never > gives up > the GIL when moving into native code and we probably should. I have > not yet > researched what we should do with callbacks from Objective-C to > Python. > > E.g. the NSApplicationMain wrapper should release the GIL before > calling > the actuall function, but how do you regain the GIL during calls to > methods > implemented in Python? I have sample code to do this, based on pthreads. You can have it if you want it, but it's probably just as easy to recode it (as you'll have to replace the pthreads stuff anyway, I would guess). The trick I used is to put pthread's per-thread data to work (I assume ObjC threads have a similar feature, yes?). You allocate an item of per-thread global data, which is automatically initialized to zero in all threads. Then when you switch from Python->ObjC you store the current PyThreadState in there. When you switch from PObjC to Python you get the per-thread global data item. If it is non-null it is the PyThreadState and you simply do PyEval_AcquireThread. If it is null then this is a thread that has never yet made the Python->ObjC transition. As it is apparently executing ObjC code right now it must have been created outside of Python. So, you create a new PyThreadState for it (with PyThreadState_New), store that in the per-thread global data and call PyEval_AcquireThread. -- - 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: pluto <pl...@ob...> - 2002-10-28 09:42:11
|
hi folks, i'm new to this list, i'm also new to macs and obj-c. i've been programming python for a several years as a living... and thats enough of an intro ;-) On Monday, October 28, 2002, at 01:00 AM, Ronald Oussoren wrote: > All, > > I just remembered one implementation issue that should be worked on > before reaching a 1.0 release: Thread safety. > > The current code is probably save for multi-threading, but I haven't > really checked this. Basicly I removed all static/global buffers while > working on the code. > > There are some more issues: > 1. Python has a global interpreter lock. When one thread owns this > lock, no > other thread can execute python code. The bridge currently never > gives up > the GIL when moving into native code and we probably should. I have > not yet > researched what we should do with callbacks from Objective-C to > Python. > > E.g. the NSApplicationMain wrapper should release the GIL before > calling > the actuall function, but how do you regain the GIL during calls to > methods > implemented in Python? > write a (objective) c wrapper that gets registered for the callback and takes a pointer to the python object to call. on callback reacquire the gil and call the object. > This is necessary to avoid unecessary blockage of Python threads > during > calls to Objective-C code. > > 2. Threads started using the Cocoa thread class(es) won't have a python > interpreter state. Special wrapping code should be written to > arrange for the > creation of that state. This can wait until item 1 is finished. > maybe it would be helpful to look at what pyqt or wxpython do in such cases. cheers, -p |
From: Ronald O. <ous...@ci...> - 2002-10-28 09:00:41
|
All, I just remembered one implementation issue that should be worked on before reaching a 1.0 release: Thread safety. The current code is probably save for multi-threading, but I haven't really checked this. Basicly I removed all static/global buffers while working on the code. There are some more issues: 1. Python has a global interpreter lock. When one thread owns this lock, no other thread can execute python code. The bridge currently never gives up the GIL when moving into native code and we probably should. I have not yet researched what we should do with callbacks from Objective-C to Python. E.g. the NSApplicationMain wrapper should release the GIL before calling the actuall function, but how do you regain the GIL during calls to methods implemented in Python? This is necessary to avoid unecessary blockage of Python threads during calls to Objective-C code. 2. Threads started using the Cocoa thread class(es) won't have a python interpreter state. Special wrapping code should be written to arrange for the creation of that state. This can wait until item 1 is finished. Ronald |
From: Ronald O. <ous...@ci...> - 2002-10-28 08:51:51
|
Jonathan, I agree that we should try to abstract away manual management of reference counts. Until a few days ago I believed we already reached this point. There are now two sets of ... 1. Bill mentioned that it is common in some Objective-C code to transfer ownership of returned objects to the caller (He's the resident expert on these issues, I'm learning Objective-C/Cocoa as a go along). It will be hard to correctly identify all these cases. IMHO this shouldn't keep us from doing away with autorelease/release/retain in Python code: it will just be a little harder to correctly wrap an Objective-C class library. As wrapping an Objective-C class is an order of magnitude simpler than wrapper other 'native' code that should not be a problem. 2. Bill also mentioned a coding style that uses 'autorelease' to make sure that an object is around to the end of the current loop through the eventloop (which in case of non-GUI programs may be quite a long time). I don't really like this coding style, so IMHO it is not a problem to use 'obj.retain().autorelease()' in these cases, instead of just 'obj.autorelease()'. I'm also pretty sure that doesn't really have anything to do with the automatic management of refcounts by the bridge. 3. The NSMutableArray class cluster (and probably all NS<DataStructure> class clusters) play games with reference counts during allocation. This is not a problem if you use the common Objective-C idiom, but it is when you try to automate management of reference counts. Basicly the issue is that the Objective-C manual strongly suggest that the following two lines should be equivalent, but they are not for these class clusters: NSArray.alloc().autorelease().init() # Basicly what the bridge does NSArray.alloc().init().autorelease() # Common Objective-C idiom I'm thinking on how to fix this. The one requireing the least amount of engeneering is saying "Don't use 'alloc().init()' for these class clusters", or even "Don't allocate Objective-C containers from Python". I don't really like this and am thinking on how to fix this in a correct manner. Ronald |
From: Jonathan L. <pan...@sk...> - 2002-10-28 05:35:34
|
Guys, I have been watching the discussion on retain/release/autorelease semantics for a few days and I have put some thought into things. After a lot of thought, I would like to sincerely urge you to make an attempt at abstracting out any and all retain/release/autorelease responsibilities for the programmer. I understand the argument that it isn't very "Cocoa-like", but I feel that I have a compelling argument here. First, I believe that you alienate most python programmers by enforcing memory management on them. Python programmers use python *because* they don't have to worry about this kind of thing. Its not that they don't know how or are afraid of it, they just don't want to touch it. If you force people into it, they will likely end up using wxPython or something like REALBasic. Secondly, to counter the "Cocoa-like" argument, placing memory management functionality into a python product is simply not "Python-like". Sure, it will feel more like developing with Cocoa and Objective-C, but people are going to use the Python bridge because they don't want to work with Objective-C when they don't have to. You have to make a choice here... if PyObjC is for Cocoa developers who don't know python, then certainly you should try and be "Cocoa-like." But if PyObjC is for *python programmers* (which I have a feeling it is), then it should strive to be Python like... meaning no retain/release at all! My last point is that I believe this project is a unique opportunity to take the already simple and powerful Cocoa development frameworks and make them even more elegant. Python has a powerful ability to help developers implement or prototype things QUICKLY. Memory management through old-style reference counting stands directly opposite to this power. If you lose this, why use Python at all? You might as well just use Objective-C (it only takes a few minutes to learn) and is faster than python. When I switched to Mac OS X a few months ago, I had been using Java Swing, wxPython, and GNOME's Python bindings to build GUI applications. On OS X, I really wanted to be able to leverage the native widgets and native frameworks to their fullest potential using a language that I was comfortable with. I tried out the Java bridge and was terribly disappointed with speed, documentation, and general instability of the bridge. Then I bit the bullet and learned Objective-C. I was impressed overall, but really felt that the memory management system was pathetically outdated and cumbersome. Its certainly better than C, but definitely not as simple as my previous solutions. When this project came along I was extremely excited about the possibilities that it offered. Please consider at least making an automated system an OPTION. I know its hard, but I think that in the long run it will be worth it. A system like Cocoa without manual memory management using a language like Python and Mac OS X's developer tools is such a powerful concept and could truly be the "killer app" of development on Mac OS X. Just some food for thought... - Jonathan |
From: Bill B. <bb...@co...> - 2002-10-27 22:44:29
|
On Friday, October 25, 2002, at 09:31 AM, Jack Jansen wrote: > Bill, > a couple of questions on your architectural remarks. > On Friday, Oct 25, 2002, at 02:40 Europe/Amsterdam, Bill Bumgarner > wrote: >> Bugs & Architecture: >> >> - there should be a way in the GUI to open a file into the >> settings -- i.e. the Open... command should be "Run script..." and >> "Open..." should truly open the script as a document. [...] >> >> - the 'run in terminal' button doesn't update the field contents >> and, as such, the contents can get out of sync... >> >> - If the multi-doc architecture is going to be used, there should >> be something to save! [...] >> Finally, the app really isn't a multiple-document type app. [...] > > All these hinge on the fact that PythonLauncher looks like a > multidocument application, but really isn't. Is that a problem? I > modeled the semantics more-or-less after Stuffit Expander: > PythonLauncher can operate in 2 modes, one where it's already running > (and opening a document always goes into interactive mode) and another > one where the application is started for a single document, which is > launched (optionally after allowing interaction to set the options) > after which PythonLauncher quits without further ado. Ahh... OK -- that clarifies things a bit and I'll modify my comments accordingly. I could see use for a multi-doc app if one were to want to save per-script configuration information but, as you indicate, there isn't a whole heck of a lot of value in that. A console might be nice, though, and that would open the need to leave the app running. >> - If I use the new menu item, it doesn't seem possible to set the >> script to be executed by the document. > > That's because I haven't been able to disable the New command, which > is what I really would want to do. Can you tell me how to do this? > (Or, better, tell me where I should have found the information) In a multiple document architecture app, the 'new' menu item is bound to newDocument: on the First Responder. If it should always be disabled, why not just delete the menu item? In any case, you can use Cocoa's automatic menu validation to disable the menu item. Implement the following method on the application's delegate: - (BOOL)validateMenuItem:(NSMenuItem *)aCell { SEL action = [aCell action]; if (action == @selector(newDocument:)) return NO; return YES; } -validateMenuItem: can be implemented on any object in the responder chain. Whenever a menu is popped down, the method is called for each cell in the menu -- the invocation of methods follows the same pattern as the responder chain. I.e. first responder view -> superview -> superview -> ...etc... -> window -> window's delegate -> app -> app's delegate. If you don't have any documents/windows on the screen, then the responder chain is just app -> app's delegate and, in this case, means you want to return NO for the newDocument: item from the app's delegate's implementation. >> - Since both the preferences window and the documents have the >> same interior UI, the NIB file for that UI should be split out and >> the preferences and document window should share that single NIB. >> The preferences window should likely move to a tabbed view with the >> different file types in the tabs -- that seems to be the HIG way >> these days. > > Again, I wanted to do this but I haven't been able to come up with a > way to do it. Please enlighten me. There's actually two things that I > haven't been able to find out: > 1. How can I share the interior contents of two windows? First, create a new nib file that contains a Custom View in it (a Custom View is just a container for other views, in this instance -- kind of like a window in a regular nib file). Stick the shared UI into this NIB file. The trick is that the file's owner doesn't have to be the same class as it is in the runtime-- it just needs to be the instance of some class that defines the same set of actions and outlets as are used in IB. An alternative would be to make the Settings class control the UI elements -- if the outlets are non-nil, it keeps the UI up to date and monitors user interaction with the UI. An instance of settings could then be passed as the owner. Then, when you load either the preferences panel or a script window's NIB, load this second NIB as well. Now that you have all the UI elements loaded, the trick is to shove 'em into the window. This is mostly a case of moving the various views around to make room for the new chunk of content. Very likely, the easiest solution is to simply dump a custom view into the window. Resize it to be in the position and of the same size as the chunk of UI you are going to be sharing between the two windows. Add an outlet to the PreferencesWindowController and MyDocument classes that connect to the view to be replaced. Then, in awakeFromNib:, do something like: [[viewToBeReplacedWithRealContents superview] replaceSubview: viewToBeReplacedWithRealContents with: customViewThatContainsTheSharedContentsInThatOtherNibFile] More sane variable names would likely be preferable... (For the preferences controller, there is no need to do the view swap thing as the TabView already has a view in it that can be used to swap the UI elements in as necessary. > 2. How do I get a tabbed view without actually having something > different on every tab (I want the same controls on each tab, really, > and I don't want to duplicate either the code or the controls)? Good question. I don't... didn't... know. I gave it a try and it boils down to a one liner (I love Cocoa that way :-). Set your window controller (document, whatever) to be the delegate of the Tab View. Then, implement something like: - (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem; { // share the shared UI elements across all tabs. Use -identifier to figure out which tab was selected if you want to do so passively. Alternatively, use [[tabView selectedTabViewItem] ...] or create three outlets to the tab view items and simply do == when updating / reading from the UI. NSLog(@"Did select tab %@ (%@)", [tabViewItem identifier], [tabViewItem label]); [[[tabView selectedTabViewItem] view] addSubview: sharedUIElements]; } To make sure *something* is displayed when the nib is loaded, do the following in, say, -awakeFromNib: [[[tabView selectedTabViewItem] view] addSubview: sharedUIElements]; You can grab the example from the following URL -- it is bogus save for the tab view manipulation. It also shows how to programmatically create tabs -- may be necessary if you want to support a dynamic list of configurations or something similar. http://www.friday.com/software/examples/tabtest.tgz >> - NSTask would be a better candidate than system() to subshell >> out the command. It would allow the app to monitor the output and >> display a console. > [...] >> The first step in moving to a true multi-doc style app is for the app >> to give the user control over when documents are closed -- that is, >> if a user opens a python script [as opposed to Running... a script >> without opening a visible document at all], the associated window >> should remain open until the user tells it to go away. The document >> should have a notion of 'currently running, do you want to launch >> another instance of the same thing?' and 'abort/stop current run'. > > These are things I specifically don't want to do (i.e. convince me > otherwise if you think it's worthwhile). The intention of > PythonLauncher is to be like Java AppletLauncher (or the above > mentioned Stuffit Expander): it should "fire and forget" the script. > Remember, the reason this was written in the first place is because > CFBundleTypeRole=Shell doesn't work (which is what it's trying to > emulate, with the options dialog thrown in so that we no longer have > to provide that in pythonw, and have the functionality for console > scripts too). Ideally a naive user shouldn't even be aware of the fact > that this thing exists. I'm all for keeping it as simple as possible. If someone really wants to have more control over the execution of a script, then they can use the IDE or command line directly. Given the clarification as to the design goals provided above, these requested features are pretty much out the window-- but they would be nice to have in other contexts... b.bum |
From: <bb...@ma...> - 2002-10-27 18:51:05
|
Sebastian, The Web Services Tool example project contains everything within it=20= to support automatic linking of frameworks into the Python runtime as=20 the app starts up. Once you create a new Cocoa-Python project, add a framework target=20= to the project. Put only classes that you want compiled into that=20 target. Then, in the app target, add a "Copy files" build phase and=20 copy the built framework into the "Frameworks" subdirectory of the=20 application (it is an option in the pop-up for the build phase=20 inspector). If you have everything set up correctly, the framework will be=20 dynamically loaded automatically by the code in Main.py. If you add an=20= Init.py python scripts as a Resource in the framework target, it will=20 be automatically evaluated immediately after the framework is=20 dynamically loaded. This allows you to import any other python code=20 that you might need (the framework's Resources directory is=20 automatically added to Python's sys.path). Unfortunately, the Cocoa-Python project template does not currently=20= include the correct code. When you create a new Cocoa-Python project,=20= simply replace the contents of the main.m and the Main.py file with the=20= contents from the same files in the Web Services Tool project. I hope to have a chance to make a real tutorial out of this stuff,=20= that and write some documentation.... b.bum On Saturday, October 26, 2002, at 05:18 AM, S=E9bastien Pierre wrote: > Hi, > > I am writing an Objective-C library that I'd like to import and use in=20= > Python through pyobjc. > > Is it possible to do this? If so, what do I have to do to make my=20 > library available to python ? > > TIA, > > -- S=E9bastien |
From: Ronald O. <ous...@ci...> - 2002-10-27 18:18:35
|
On Saturday, Oct 26, 2002, at 11:18 Europe/Amsterdam, S=E9bastien Pierre=20= wrote: > Hi, > > I am writing an Objective-C library that I'd like to import and use in=20= > Python through pyobjc. > > Is it possible to do this? If so, what do I have to do to make my=20 > library available to python ? It is quite easy to do this, assuming that you want to access the=20 classes in the Objective-C library and the library is in a framework. If your library is installed in the framework=20 '/path/to/mylib.framework' you can do something like this: # This is 'mylib.py', a python library for accessing classes # in 'mylib.framework' import Foundation class_list =3D Foundation.load_bundle( '/path/to/mylib.framework') gl =3D globals() for cls in class_list: gl[cls.__name__] =3D cls del class_list, cls, gl, Foundation # end of mylib.py This will load 'mylib.framework' and export all classes in that=20 framework. Ronald= |
From: <sp...@al...> - 2002-10-26 09:18:59
|
Hi, I am writing an Objective-C library that I'd like to import and use in=20= Python through pyobjc. Is it possible to do this? If so, what do I have to do to make my=20 library available to python ? TIA, -- S=E9bastien PS: I am rather new to Objective-C and the difference between libraries=20= and framework is rather unclear... -- =ABIl vaut mieux suivre une voix stupide que l'on connait, plut=F4t qu'une intelligente que l'on ne connait pas.=BB <http://www.type-z.org> -- No comment on Jacques C.= |
From: Bill B. <bb...@co...> - 2002-10-25 21:00:56
|
On Friday, October 25, 2002, at 04:06 PM, Ronald Oussoren wrote: > Bill, > > The 'fix' was not your change to 'objc_support.m', but the change to > 'selector.m' (the one I'm so unhappy about ;-() Yes -- I undid the change in objc_support.m and committed the unmodified version. Sorry. Should have undid that. > The problem is that NSMutableArray isn't really following the Cocoa > refcounting conventions. This can be demonstrated using a simple > Objective-C program: That the NSArray class cluster uses a placeholder upon allocation isn't a violation of the Cocoa refcounting conventions -- it is just fallout from the design of the class cluster. There is nothing that says that what is returned by +alloc must be the same instance as whatever is returned by -init. > Note that return value of the two calls of alloc is the same, and > different from the return value of the corresponding init calls. > Appearently 'alloc' just returns a kind of factory object, and 'init' > is the one that actually allocates memory. > Further investigation shows that the return value of 'alloc' is a > 'NSPlaceholderMutableArray'. Actually it is probably that class and > not an instance of it. Both 'x->isa->name' and 'x->isa->isa->name' are > 'NSPlaceholderMutableArray', if 'x' where an object I'd expect the > second to be 'NSObject'. The NSArray class cluster returns a placeholder [factory] for allocation because it does not yet have enough information to determine which private subclass will most efficiently hold whatever the developer is about to throw at it. > I'm glad to find that the problem with NSArray is caused by a feature > of Cocoa and is not a memory corrupting bug in PyObjC itself. That > doesn't make it easier to actually fix it of course, but at least we > can now start to think about how to really solve this instead of > hunting down an elusive memory corruption > error. That the placeholder is both shared, but allows itself to be released to the point of destruction, would seem to be something that Apple would have wanted to avoid by simply overriding -release on the placeholder class and having it do nothing. This would, at least, prevent an app from crashing in a bizarre fashion because the cached placeholder instance has blown up. Then again, maybe they are playing interesting internal games with the retain count. The implementation of the placeholder class itself does seem to be a bit odd. b.bum |
From: Ronald O. <ous...@ci...> - 2002-10-25 20:06:39
|
Bill, The 'fix' was not your change to 'objc_support.m', but the change to 'selector.m' (the one I'm so unhappy about ;-() The problem is that NSMutableArray isn't really following the Cocoa refcounting conventions. This can be demonstrated using a simple Objective-C program: #import <Foundation/Foundation.h> int main(void) { id x; printf("class: %p\n", [NSMutableArray class]); printf("alloc: %p\n", x = [NSMutableArray alloc]); printf("init: %p\n", x = [x init]); printf("alloc: %p\n", x = [NSMutableArray alloc]); printf("init: %p\n", x = [x init]); } The output on my system: class: 0xa07ec7b8 alloc: 0x875a0 init: 0x8e7a0 alloc: 0x875a0 init: 0x8e7c0 Note that return value of the two calls of alloc is the same, and different from the return value of the corresponding init calls. Appearently 'alloc' just returns a kind of factory object, and 'init' is the one that actually allocates memory. Further investigation shows that the return value of 'alloc' is a 'NSPlaceholderMutableArray'. Actually it is probably that class and not an instance of it. Both 'x->isa->name' and 'x->isa->isa->name' are 'NSPlaceholderMutableArray', if 'x' where an object I'd expect the second to be 'NSObject'. I'm glad to find that the problem with NSArray is caused by a feature of Cocoa and is not a memory corrupting bug in PyObjC itself. That doesn't make it easier to actually fix it of course, but at least we can now start to think about how to really solve this instead of hunting down an elusive memory corruption error. Ronald |
From: Bill B. <bb...@co...> - 2002-10-25 14:59:03
|
On Friday, October 25, 2002, at 05:22 AM, Ronald Oussoren wrote: > On Thursday, Oct 24, 2002, at 23:40 Europe/Amsterdam, Bill Bumgarner > wrote: >> ... which is exactly a 1 for 1 correspondance to calls to alloc() >> from within Python. I had been writing my code like... >> >> toolbarItem = >> NSToolbarItem.alloc().initWithItemIdentifier_(anIdentifier) >> toolbarItem.autorelease() >> >> ... but under the code implied by the -release above, I should not be >> calling autorelease(). Makes sense. > That was my idea: Conversion from Objective-C to Python implies > removing all calls to 'retain', 'release' and 'autorelease'. In general, this is great. I'm still concerned about the differences in behavior that it implies when it only affects a handful of methods. >> However, I'm not 100% sure that it is the correct pattern. I.e. do >> we really want to make the bridge responsible for keeping track of >> every single method that causes object allocation and do the -release >> as the current code does? > Yes, this makes the bridge as transparent as possible. Asking the > programmer to *sometimes* worry about reference counts is confusing. I > added the code above to PyObjC to make sure I never have to think > about reference counts when programming in Python. The developer still has to sometimes worry about reference counts and has to do so in a fashion that doesn't come naturally [in my experience]. We are really talking about a couple of different behaviors. First, there is the behavior that an assignment or set membership within Python implies a -retain. To balance the implied -retain, removal from a set or destruction of the assignment implies a -release. This seems to come naturally to most developers and is quite consistent across the environment. -- The second behavior is that any call to +alloc, +allocWithZone:, +copy, +copyWithZone:, and +mutableCopyWithZone: implies a -release as the object comes into the Python environment. This changes the meaning of these methods in Python-- the developer can no longer look up the documentation of the method and believe what Apple has to say! Instead, the developer has to effectively raise a mental exception and remember that these methods no longer mean what they used to mean. I'm [very likely] the first person to use this feature besides you and look at the problems it caused me! I was expected those methods to behave exactly as they do in ObjC, but they didn't and the resulting behavior was-- as is often the case with retain/release/autorelease bugs-- incredibly difficult to track down and fix. Even now that I'm familiar with the behavior, I'm still want to write the same [[[... alloc] init] autorelease] idiom that is the defined standard within Obj-C. The implementation also makes the assumption that those are the only methods that return retained instances of an object-- the only methods that transfer ownership. It even mentions... # These 5 are documented in Apple's Objective-C book, in theory these # are the only methods that transfer ownership. ... but, already, there is a discrepancy! The +new method also transfers ownership -- it is just a cover for [[... alloc] init]. Speaking of the +new method, a common design pattern is to implement factory methods of the form +newWith... or +newBy... or +newFrom... or +new* where the ... or * is replaced by some indication as to how the newly created object shoudl be configured. All of these methods return alloc/init'd instances of the object and all transfer ownership to the caller. And what about the different forms of copy? -deepCopy and -deepMutableCopy immediately come to mind. As well, I have seen (and occasionally written) convenience methods that do things like copy the contents of an NSImage, returning a new NSImageRep that is -retain'd or copied the contents of an NSTextView and returned a -retain'd NSTextStorage. Now the developer has to remember the 5 methods that are different [6, really] and they have to remember that any other method that 'transfers ownership' works the old way. > Due to a 'feature' of NSOutlineView I still have to worry about this, > but that is a different story. In short: NSOutlineView doesn't > 'retain' the results of outlineView:child:ofItem:, but does hang on to > this value. This means you cannot use python objects as return values, > because their proxies are autoreleased and NSOutlineView tries to > access these proxies after they are released... IMNSHO this is a bug > and I'm thinking of fileing a bug report on this. It is expected it to survive beyond the end of the current pass through the main event loop? That's definitely broken. I.e. this'll break it? - outlineView:child:ofItem: { return [NSString stringWithFormat: @"%d %d", 1, 2"]; } >> ... extra details deleted ... >> This subtly, but significantly, changes the object lifespan patterns >> pervasive throughout the foundation. While this particular example >> is somewhat bogus, there are other situations where such a lifespan >> change could cause a failure. Example: the developer creates a >> class whose instances listen for a particular notification and remove >> themselves as observers when dealloc'd. A common idiom for creation >> might be MyChangeListener.alloc().init().autorelease(), but that >> isn't possible with the current implementation of the bridge. > 'a common idiom for creation MIGHT be': Is this really a common idiom? > I'd rather not worry about theoretical changes. As far as I can judge > right now the current policy of fully automaticly managing reference > counts is far more usefull than manually updating them. Common? No, but it is a pattern that I use and have encountered in looking at other developer's code (several times throughout my career, I have been in a developer support role). I have been building developer tools for a long, long time -- one of the lessons that has been beat into my thick skull over the years is that I will never be able to predict how the community of developers using my code is going to use that code. If I can imagine it, there are probably 10 other things I didn't imagine that some developer will try to do! > BTW. If you really want to use autorelease you could always do > 'obj.retain();obj.autorelease()'. This is different from the > Objective-C way of doing this, but at least it is clear you're doing > something fishy. And this is pretty fishy: In most programs 'at least > as long as the current threads current autorelease pool' is 'at least > until the start of the next round throught the event loop', which is > probably a very short time. Event loops aren't just for processing user events. In WebObjects (which used to be an Obj-C app), one pass through the event loop involved parsing and responding to an entire HTTP request. Now that Web Services are all the rage, handling an HTTP request inside of a Cocoa application is gaining in popularity and the most common way to do so is using a similar one-request-per-pass-through-run-loop model (this is exactly what I'm doing in two of my apps now). Handling an HTTP request is a considerably more complex process than handling a keystroke. To further compound the complexity, there is often some kind of a persistent backing store that may have to be read from and/or written to. Instead of validating just one field of user input, an HTTP request may have to validate a couple of dozen hunks of user input all at once. If this is through to a backing store of some kind, there is typically several layers of delegated validation occurring during the whole process. Because there is often some concept of a session -- roughly equivalent to a Document -- there is often change notifications flying around the system and listeners of change notifications. Run loops are also used to do other kinds of 'event' processing; calculation engines, data gathering, timed event, background processes, distributed objects, etc... > BTW2. I really don't like 'invisible' objects like the > MyChangeListener example. How am I as a code maintainer/reviewer to > know that this is the intended behaviour and not an attempt to work > around another bug (at least this doesn't leak memory). The 'invisible' object is a design pattern found throughout the AppKit, the Foundation, EOF, and a number of other object oriented kits. NSNotificationCenter is at the heart of it. As something -- an application, a athread, a whatever -- is initialized, various random objects have the opportunity to act as notification listeners. The objects posting the notifications don't have any clue what, if anything, is listening for the notifications. To put this into context; say, I create a bundleized app-- Project Builder's PBX Bundles and Interface Builder's Palettes are both good examples. Within that app within a single run loop, I post a notification of 'prepare to change object graph', followed by a series of 'changing object graph' notifications' and -- if everything went well -- a 'done changing the object graph' notification. Now, during one of the 'changing object graph' notifications, an exception is raised and the 'done changing' notification never gets posted. A bundle author may create a bundle that listens for the 'prepare' notifications. When received, that bundle then creates a listener for 'changing' and 'done' notifications that is highly customized to the userInfo dictionary contents passed in the 'prepare' notification. In this case, the only way the object will be deallocated is if it is in the autorelease pool! (I ran into this situation when writing an IB palette recently) >> As well, there is no way we can ever quantify all possible methods >> that a developer might use to produce a freshly allocated object that >> the current code would need to -release to preserve the pattern as it >> exists now. > Yes we can. Apple clearly documents in the Objective-C reference > manual that only a small number of methods should return objects that > you don't have to 'retain' (basicly alloc and copy). If you get an > object in any other way you should call 'retain' yourself. As much as > a dislike the idea of 'autorelease' it does solve the problem of > object ownership (why couldn't Objective-C use a real garbage > collector and do away with manual memory managment?). As indicated above, the documentation is wrong. As well, any developer can come along and create new methods (the +new...: pattern is actually quite useful) that the API will not be aware of. The retain/release implied by assignment and set membership is that it is ubiquitous to messaging through the bridge. Modifying the behavior of a handful of methods is not ubiquitous and, as such, will never achieve 100% coverage-- this will lead to confusion and bugs. (Because C is a pointer based language, an Obj-C garbage collector-- there are a few available-- can never achieve 100% coverage....) > If a developer writes classes that don't follow this convention that > is a bug, plain and simple. Such code is even a problem for plain > Objective-C users: Given the text in the Objective-C manual users will > expect they have to retain the result of method calls, a method that > does not follow this convention is confusing and is bound to introduce > memory leaks. > > As should be obvious by now I am not convinced at all that the current > policy of PyObjC is wrong. I'd like to see a real-live example of why > the current policy is bad before I change my position. Examples -- all culled from code that I have encountered recently (names changed to protect the guilty): foo = [NSObject new] bar = [someObject deepCopy] baz = [myDictionary deepMutableCopy] bob = [aCollection copyWithConvertedValues] Scanning my source tree-- a tree containing piles of my own code, code of my clients, and code from numerous third parties-- using... find . -name '*.m' -exec grep -H -e '+.*new.*' {} \; I find about 20 instances where I or others have implemented a +new... method that returns a retained object. That is just looking for +new... and does not include the other cases where a developer decided that they-- for whatever reason, some may be invalid-- wanted to return a retained instances of something. Searching through /Developer/Examples/ turns up a couple of examples where +new... is used in a fashion that does not return a -retain'd instance. So much for consistency... b.bum |
From: Jack J. <Jac...@cw...> - 2002-10-25 13:31:36
|
Bill, a couple of questions on your architectural remarks. On Friday, Oct 25, 2002, at 02:40 Europe/Amsterdam, Bill Bumgarner wrote: > Bugs & Architecture: > > - there should be a way in the GUI to open a file into the > settings -- i.e. the Open... command should be "Run script..." and > "Open..." should truly open the script as a document. [...] > > - the 'run in terminal' button doesn't update the field contents > and, as such, the contents can get out of sync... > > - If the multi-doc architecture is going to be used, there should > be something to save! [...] > Finally, the app really isn't a multiple-document type app. [...] All these hinge on the fact that PythonLauncher looks like a multidocument application, but really isn't. Is that a problem? I modeled the semantics more-or-less after Stuffit Expander: PythonLauncher can operate in 2 modes, one where it's already running (and opening a document always goes into interactive mode) and another one where the application is started for a single document, which is launched (optionally after allowing interaction to set the options) after which PythonLauncher quits without further ado. > - If I use the new menu item, it doesn't seem possible to set the > script to be executed by the document. That's because I haven't been able to disable the New command, which is what I really would want to do. Can you tell me how to do this? (Or, better, tell me where I should have found the information) > - Since both the preferences window and the documents have the > same interior UI, the NIB file for that UI should be split out and the > preferences and document window should share that single NIB. The > preferences window should likely move to a tabbed view with the > different file types in the tabs -- that seems to be the HIG way these > days. Again, I wanted to do this but I haven't been able to come up with a way to do it. Please enlighten me. There's actually two things that I haven't been able to find out: 1. How can I share the interior contents of two windows? 2. How do I get a tabbed view without actually having something different on every tab (I want the same controls on each tab, really, and I don't want to duplicate either the code or the controls)? > - NSTask would be a better candidate than system() to subshell out > the command. It would allow the app to monitor the output and display > a console. [...] > The first step in moving to a true multi-doc style app is for the app > to give the user control over when documents are closed -- that is, if > a user opens a python script [as opposed to Running... a script > without opening a visible document at all], the associated window > should remain open until the user tells it to go away. The document > should have a notion of 'currently running, do you want to launch > another instance of the same thing?' and 'abort/stop current run'. These are things I specifically don't want to do (i.e. convince me otherwise if you think it's worthwhile). The intention of PythonLauncher is to be like Java AppletLauncher (or the above mentioned Stuffit Expander): it should "fire and forget" the script. Remember, the reason this was written in the first place is because CFBundleTypeRole=Shell doesn't work (which is what it's trying to emulate, with the options dialog thrown in so that we no longer have to provide that in pythonw, and have the functionality for console scripts too). Ideally a naive user shouldn't even be aware of the fact that this thing exists. -- - 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-25 11:08:48
|
On Thursday, Oct 24, 2002, at 02:01 Europe/Amsterdam, bb...@ma... wrote: > As Ronald indicated, you have to manually create the subclass of > NSObject (or whatever) in IB. Unfortunately, we don't currently have > a "create source files" that'll create Python source from within IB. > Well, maybe not true -- I saw in the repository that Ronald has > another bit of magic in the works. :-) This 'magic' is already in the installer on your site, I just haven't wired it up yet. And now on to a description of this magic feature... When you define a user-interface in Interface Builder one of the files that is written into the NIB named 'classes.nib'. This is a text file containing a description of the classes that are defined in the NIB. I've written a python module that can be used to read this file and generate a module containing class definitions. In your own code you just import this module and subclass from the generated classes to define the classes from the NIB. Advantages are: - No need to manually define 'IBOutlet' entries (outlets in Interface Builder) - No need to manually specify the signature for actions - No manual sync between definitions in IB and python code. I'll probably change one or more of the examples to use this script, but that will have to wait until we've fixed some problems with the C code and have written some more tests and documentation. Ronald |