Re: storage for context: value
On Jul 25, 2013, at 12:08 , Matt Neuburg wrote: > Well, and discussions of the issue often fail to take into account the > problem of distinguishing the context on an instance-by-instance basis. > Passing "self" as a context does that, obviously; but the "static void*" > trick does not (there is one storage per class, not per instance of that > class). In the 'observeValueForKeyPath' scenario (keeping in mind that it's a broken API design), using 'self' is dangerous because it's not unique enough. A superclass-defined observation may cleverly try to use it too. > If an informative data structure is to be used on an instance-by-instance > basis, and if this data structure is to persist, then it seems to me that it > *must* be an instance variable. When you say "instance variable" I think there are actually 3 different possibilities: 1. You want a per-instance value, which is stored in an ivar specifically for that purpose. 2. You might get away with using the address of an ivar that's private to your class (whose value is something unrelated). The address is unique to the instance and class, because superclasses and subclasses won't be using it. 3. You might still need a per-observation-per-instance context tag, in which case #1 and #2 don't work. This is particularly relevant to the new form of 'removeObserver'. If it were me, I would use a per-class tag (such as the static variable address) when I could, or a per-observation UID otherwise. Using a per-instance UID -- anything unique only to the level of 'self' -- seems too dangerous these days. The likelihood of the class having -- or later adding -- multiple observations on the same thing seems too high. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: storage for context: value
Well, and discussions of the issue often fail to take into account the problem of distinguishing the context on an instance-by-instance basis. Passing "self" as a context does that, obviously; but the "static void*" trick does not (there is one storage per class, not per instance of that class). If an informative data structure is to be used on an instance-by-instance basis, and if this data structure is to persist, then it seems to me that it *must* be an instance variable. m. On Jul 25, 2013, at 9:19 AM, Quincey Morris wrote: > On Jul 25, 2013, at 07:20 , Matt Neuburg wrote: > >> storage of the value passed as context:(void*), not just in addObserver:, >> but in general > > I think I'd take this in a different direction. In *all* of these scenarios > the context parameter is a mechanism for passing a pointer to a data > structure to a callback/completion routine/handler with a generic signature, > as Roland already said. > > That leads to a set of potential pitfalls: > > -- Memory management. If the data structure is allocated memory (C idiom) or > an object (ObjC idiom), it's not trivial to manage its lifetime. > > -- Heterogeneity. If contexts of different idioms are fed to the same > handler, it can be difficult to decide what data structure is being pointed > to. > > -- Complexity. If the data structure pointed to is just a single value (such > as a simple type, or a simple identifier), it can take a lot of code to > package this in a real data structure that behaves properly wrt the first 2 > pitfalls. > > The 'static void* x = &x;' convention you mention (a "pointer as tag" > convention) is significant only because it's a very elegant way to avoid all > 3 pitfalls, when no additional data needs to be passed. It also has the > virtue of relieving the developer from the need to remember whether to put a > '&' on the front of the argument. > > The story behind 'addObserver' (or, really, the story behind > 'observeValueForKeyPath') is a separate matter. This particular API was > misdesigned, because it did not properly envisage a need to identify multiple > observations of the same thing. Thus, the 'context' parameter came to be used > as this identification -- there was no actual data structure to be passed in. > The above "pointer as tag" convention bubbled to the top of the pile as the > most convenient way to solve the problem. > -- matt neuburg, phd = m...@tidbits.com, http://www.apeth.net/matt/ pantes anthropoi tou eidenai oregontai phusei Programming iOS 6! http://shop.oreilly.com/product/0636920029717.do RubyFrontier! http://www.apeth.com/RubyFrontierDocs/default.html TidBITS, Mac news and reviews since 1990, http://www.tidbits.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: storage for context: value
On Jul 25, 2013, at 07:20 , Matt Neuburg wrote: > storage of the value passed as context:(void*), not just in addObserver:, but > in general I think I'd take this in a different direction. In *all* of these scenarios the context parameter is a mechanism for passing a pointer to a data structure to a callback/completion routine/handler with a generic signature, as Roland already said. That leads to a set of potential pitfalls: -- Memory management. If the data structure is allocated memory (C idiom) or an object (ObjC idiom), it's not trivial to manage its lifetime. -- Heterogeneity. If contexts of different idioms are fed to the same handler, it can be difficult to decide what data structure is being pointed to. -- Complexity. If the data structure pointed to is just a single value (such as a simple type, or a simple identifier), it can take a lot of code to package this in a real data structure that behaves properly wrt the first 2 pitfalls. The 'static void* x = &x;' convention you mention (a "pointer as tag" convention) is significant only because it's a very elegant way to avoid all 3 pitfalls, when no additional data needs to be passed. It also has the virtue of relieving the developer from the need to remember whether to put a '&' on the front of the argument. The story behind 'addObserver' (or, really, the story behind 'observeValueForKeyPath') is a separate matter. This particular API was misdesigned, because it did not properly envisage a need to identify multiple observations of the same thing. Thus, the 'context' parameter came to be used as this identification -- there was no actual data structure to be passed in. The above "pointer as tag" convention bubbled to the top of the pile as the most convenient way to solve the problem. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: storage for context: value
On Jul 25, 2013, at 8:50 AM, Matt Neuburg wrote: > But surely that can't work, since you set up the call once but you can get > called back many times - or am I misunderstanding? m. Sorry, that depends on the callback, and I was thinking specifically of one-shot ones. (Think of beginSheetModalForWindow…) Where the callback has an indefinite lifetime, then yes, the release must be handled somewhere else. But the basic point still applies, if you release the context info only at the point where you deactivate the callback, you're good--and yes I've done that too. Of course another way is to have an object that owns both the callback and related info, that instantiates the callback and passes itself as the context info, and deactivates the callback and releases the related info at the same time. Regardless, you need simple & clear & consistent single points of construction & destruction of the information. -- Scott Ribe scott_r...@elevated-dev.com http://www.elevated-dev.com/ (303) 722-0567 voice ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: storage for context: value
Well the second two examples of those are rather different from the first. In the case of sortedArrayUsingFunction:context: and beginAnimations:context: the context is there really as an opaque pointer to pass data into the function. That pattern of function + was the pre-blocks way to pass contextual information into a generic function, eg say you wanted to sort descending or with some options, that would go in your context in a function-dependent way. Same with beingAnimations:context: (although is anyone using that method any more? That was 'discouraged' after iOS4 and if you aren't using the block-based animations by now .. it's time) again this gave you a way to pass per-animation information in that you wanted to retrieve later. So in those cases the context would usually be a shorter-lived thing used really for the life of the call only and then discarded, often an object cast to void*. the NSKVO context. Technically I suppose you could use that in the same way, if you had an instance of an object which set up more than one observation on the same property of the same other object for more than one reason (I can't think of one offhand but it could happen) you could use the context pointer to disambiguate them and do something different in your observe... method, because you only get one observe method. Most of the time however the context in that exists not to disambiguate between multiple observations of the same property of one object registered by you, but to deal with subclasses observing the same exact property as their superclass on the same object. There will be two observations sent to the instance, each one needs to handle just one of them. In that normal case there you don't care about any actual context of where you set the observation up, you probably don't even care about which instance of your class set it up, you normally just care that this is an observation to be handled in the observe.. method implementation in that particular class, so the generic thing to use is anything at class scope, one of the easiest ways to do that is the static void *X = &X which gives you something only that class has, is already a void*. I've also used the [ xxx class ] properly cast and I think I've used the actual class instance too, probably out of idiocy. On 25 Jul, 2013, at 10:20 PM, Matt Neuburg wrote: > I'd like to hear some arguments / opinions / essays on storage of the value > passed as context:(void*), not just in addObserver:, but in general - so, > including things like beginAnimations:context: and > sortedArrayUsingFunction:context:. > > Must it always be an external variable? Must it always be stored as a void*? > I know there's a standard pattern where it's an external pointing to its own > storage: > >static void* const MYCONTEXT = (void*)&MYCONTEXT; > > Is this the only safe/sensible storage? Could it be an actual object, cast > back and forth between id and void*? Could it be stored as an ivar? Thx as > always - m. > > -- > matt neuburg, phd = m...@tidbits.com, http://www.apeth.net/matt/ > pantes anthropoi tou eidenai oregontai phusei > Programming iOS 6! http://shop.oreilly.com/product/0636920029717.do > RubyFrontier! http://www.apeth.com/RubyFrontierDocs/default.html > TidBITS, Mac news and reviews since 1990, http://www.tidbits.com > > > ___ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/rols%40rols.org > > This email sent to r...@rols.org ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: storage for context: value
On Jul 25, 2013, at 7:33 AM, Scott Ribe wrote: > If you alloc an object per callback setup, right where you set up the > callback, and release it in the callback, you're safe--and that's a very > common pattern I think But surely that can't work, since you set up the call once but you can get called back many times - or am I misunderstanding? m. -- matt neuburg, phd = m...@tidbits.com, http://www.apeth.net/matt/ pantes anthropoi tou eidenai oregontai phusei Programming iOS 6! http://shop.oreilly.com/product/0636920029717.do RubyFrontier! http://www.apeth.com/RubyFrontierDocs/default.html TidBITS, Mac news and reviews since 1990, http://www.tidbits.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: storage for context: value
On Jul 25, 2013, at 8:20 AM, Matt Neuburg wrote: > Is this the only safe/sensible storage? Could it be an actual object, cast > back and forth between id and void*? Could it be stored as an ivar? Thx as > always - m. No, of course, and yes ;-) Now the static idiom you mentioned is nice in that you don't have to worry about it going out of scope just because a function completes and the stack frame is destroyed, and because at least the variable itself does not get munged. But of course to be useful, MYCONTEXT might have to hold references to objects, and then you're back to having to manage the lifetimes of what is referred to. Also, it's only good when you only need 1 of the particular callback/info combinations to be active, and I find that's an unrealistic restriction, and is why I have (IIRC) never used this idiom. Note: I'm developing Mac software, so most of my windows/controllers can (and in normal use often will) have multiple instances existing at once. (In iOS I expect that it would be far more common to have window/controller pairs where there is never more than instance in simultaneous existence.) I think the issue of *what* the context info refers to is far far less important than the issue of controlling the contexts (harhar) in which it is managed. If you're retaining/releasing them all throughout your code, you're asking for trouble. If you alloc an object per callback setup, right where you set up the callback, and release it in the callback, you're safe--and that's a very common pattern I think. -- Scott Ribe scott_r...@elevated-dev.com http://www.elevated-dev.com/ (303) 722-0567 voice ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com