Re: [F-Script-talk] adding Blocks as methods to ObjC classes
Brought to you by:
pmougin
From: Luke N. <l_n...@ya...> - 2005-02-16 08:54:48
|
Ken, Thanks for the detailed response! I'd like to peruse your code, unfortunately I don't have permissions to access the zip file at the link you provided. I also hadn't looked at any of the JGAddon stuff in the sources. A quick glance shows that their work is far more aggressive than what I had attempted or even envisioned for my current project. However, it would be an impressive addition to F-Script to be able to dynamically add objects to the ObjC runtime system. I'm new to ObjC and even newer to F-Script, and I haven't read your code so please forgive any wrong assumptions, but it sounds like our designs seem somewhat similar, at least from the outside. With regard to type, I am actually hoping to do some intelligent return conversion between F-Script and ObjC. Recall that the prototype for the method to attach blocks as methods is: TATestingDummy attachFSBlock: [5] toSelector:#gimmefive withArgs:'' The withArgs argument is a string encoding the types of the return, two @@s for self and cmd, and whatever characters are needed to describe the desired argument types. This encoding is taken from the F-Script source, and is basically what the @encode() compiler directive would return for a function call of your method. I figured out how to do make my own encoding strings on this apple web page: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/ RuntimeOverview/chapter_4_section_6.html As the code is still in prototype form I haven't had time to fully explore what is needed to perform return type conversion. Fortunately, I seem to be relatively protected on the calling side, as these attached Block methods appear like regular ObjC method to F-Script so it is nice enough to automatically type convert the arguments to ObjC friendly types. Blocks always return id type, however, so methods interested in non-id return types will have to undergo conversion, which is informed by the withArgs: string provided at attachment time. I am also restructuring this encoding stuff to allow self to be handed in so that I can use Key Value Coding to set member variables in self, as all objects in my framework support KVC as I think cocoa bindings are almost as mind blowing as F-Script. Almost. :) I have responded to a couple of things in your email below: On Feb 15, 2005, at 1:05 AM, Ken Ferry wrote: > I've been meaning to post a similar message, so I'll throw in my 2 > cents. :-) > > I have a class that does something similar with a slightly different > emphasis. KFDecorator > <http://homepage.mac.com/kenferry/Software/KFDecorator/KFDecorator.zip> > uses message forwarding + blocks to act like an abstract decorator, > with some limitations. I think it's best explained through a couple > of examples. I don't use it in release code, but I've found it to be > pretty useful when using FScript (Anywhere) as part of the development > environment for a cocoa application. It's good for debugging, > exploration of ideas, and sometimes automated testing. > > The idea of a decorator is that it wraps a base object and modifies > its behavior. The decorator catches specified messages and processes > them, and any messages it doesn't catch are forwarded to the base > object. It's a design pattern from the Gang of Four book. > >> dataDecorator := tableView dataSource decorator > >> dataDecorator numberOfRowsInTableView:tableView > 312 > >> dataDecorator setBlock:[:self :table | 10] >> forSelector:#numberOfRowsInTableView: > >> dataDecorator setBlock:[:self :table :column :row | 'test'] >> forSelector:#tableView:objectValueForTableColumn:row: > >> dataDecorator > <KFDecorator[0x4cf5b60] base:<TableViewManager: 0x4c67a0> maps:{ > :#numberOfRowsInTableView: => [:self :table | 10] > #tableView:objectValueForTableColumn:row: => [:self :table > :column :row | 'test'] > }> Here's maybe a difference - it looks like you are adding methods to instances? I am adding methods to classes. My attachFSBlock:blahblah method is a class method. >> dataDecorator numberOfRowsInTableView:tableView > 10 > >> dataDecorator tableView:tableView objectValueForTableColumn:nil row:0 > 'test' > >> tableView setDataSource:dataDecorator > > The main interesting thing about the above example is that it shows > the decorator translating argument and return types. The > 'numberOfRowsInTableView:' method returns a genuine int, which makes > the decorator more suitable for interacting with objective-c code that > doesn't use objects. (Sounds like you did this too, Luke.) The class > was written before the latest version of FScript came out, so it uses > the deprecated Pointer class to do the dirty work. The argument and > return types are determined from the method signature of the > overridden base method, when there is such a base method. > Since my methods are actually ObjC methods on a class I am hoping F-Script wraps arguments for me. I have interest in writing type conversion for the return, but haven't needed to yet since id is a pretty useful return type for most purposes. > You can use a decorator without a base, in which case it acts more > like a dynamically built object. > >> decorator := KFDecorator decorator > >> decorator setBlock:[:self :num | num + 4] >> forSelector:#addFourToNumber: > >> decorator > <KFDecorator[0x4ca8c0] base:(null) maps:{ > #addFourToNumber: => [:self :num | num + 4] > }> > >> decorator addFourToNumber:5 > 9 > When adding a block for a method not implemented by the base, all > arguments and returns are assumed to be objects. There is a > -[KFDecorator setBlock:forSelector:withSignature:] method for when > that assumption isn't going to hold. > ah, is that an NSMethodSignature? > You can also use KFDecorator to switch between existing objective-c > methods that you'd like to evaluate. > >> decorator setBlock:#doStuff_alternateAlgorithm forSelector:#doStuff > Where in a normal subclassing situation you would call 'super', with a > decorator you can call 'self base'. The following would help you > understand under what circumstances the numberOfRowsInTableView: > method is called. > >> dataDecorator setBlock:[:self :table | sys beep. self base >> numberOfRowsInTableView:table] forSelector:#numberOfRowsInTableView: > The two biggest limitations are: > > (1) You cannot set a block for a method implemented by KFDecorator > itself, and KFDecorator is a subclass of NSObject as opposed to > NSProxy. This is because I haven't worked around NSProxy's lack of a > useful -[NSProxy methodSignatureForSelector:]. > I wrote a working version of -methodSignatureForSelector by looking at the F-Script code, maybe you can model one for NSProxy off of what I wrote. > (2) Since it's just a wrapper for a base object, you can only catch > messages when you interject the decorator between a calling object and > the base. That can be a good thing or a bad thing in different > situations. > are you using forwardInvocation? Why do you have this limitation? > Okay, so now that that's out, here are some thoughts. :-) > > I do think that JGType steals some (most?) of the thunder here, but I > haven't had much luck getting JGType to work. My app crashes whenever > I try to use the dynamic subclassing. Can we get a little bit of > sample code on that? > You've probably noticed that the first argument of every block set for > a selector is :self, which is a reference to the decorator object. In > the first version of KFDecorator I had it set up so that all of the > following worked: > >> decorator setBlock:[4] forSelector:#count > >> decorator setBlock:[ :self | 4] forSelector:#count > >> decorator setBlock:[ :self :cmd | 4 ] forSelector:#count > right I have decided on the second one as well. > I couldn't decide if it was confusing and error prone or useful, but > eventually changed it to always require the second form. Just another > thing to think about. > > Luke, I'd definitely be interested to see your version of things. We > should exchange ideas. :-) You can download my code from the link > above. > I am grooming my code to share, plus should have a usable server up in a few days (just moved) so I'll let you know when there's a zip available for DL. > -Ken > thanks again for replying! Luke > > ------------------------------------------------------- > SF email is sponsored by - The IT Product Guide > Read honest & candid reviews on hundreds of IT Products from real > users. > Discover which products truly live up to the hype. Start reading now. > http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click > _______________________________________________ > F-Script-talk mailing list > F-S...@li... > https://lists.sourceforge.net/lists/listinfo/f-script-talk > |