Re: Accessor methods and (auto)release: conclusion
Re: Accessor methods and (auto)release: conclusion
- Subject: Re: Accessor methods and (auto)release: conclusion
- From: Michael Gersten <email@hidden>
- Date: Fri, 09 Aug 2002 23:15:24 -0700
Seems to be a lot on this subject.
If I remember correctly, a long time ago, NeXT came out with the definate statement that you CANNOT rely on a vended object lasting until the end of the current block/function; if you wanted it to last and be usable later, even in the same routine, you had to retain or autorelease it. The easiest way was to store it in an Ivar of your own with a proper setter.
Yes, that was back in the NeXT days.
>
> -(void)dealloc { ... [self setter:nil]; ... }
>
>
Don't do that. Why not? A subclass could very well override the
>
setter to do something "non-simple", in which case you might be
>
triggering serious computation. Just use [var release]; (beware of
>
cycles, though).
If a subclass is overriding the setter to do something significant, then it will probably WANT to do that very same thing when it is unset.
The subclass can, for example, check to see if it is being set to nil, zero, or whatever the "turn-off" case is, and short-circut itself; or, set a flag in it's own 'dealloc', so that when the setter is called from the parent dealloc, do nothing.
That you might be overridden by a subclass that wants to know what's going on is EXACTLY WHY you do NOT just '[var release]'.
>
> or, naturally, anything *functionally equivalent* -- in other words,
>
> fulfilling the agreement "the vended object would be valid (at least)
>
> in the entire scope of the autorelease pool (current in the moment the
>
> getter vas used)". Those plain accessors you advocate alas are not!
As people have pointed out, that's not the invariant. Collections don't work that way. Nothing is required to do that. If you are given something back from another thing, it is only valid while it is still held (retained) by that other thing unless you retain it yourself.
That's been the standard since OS 4 days.
>
> Now, since collections are definitely excluded from the accessor pattern
>
> you advocate, your "invariant" does not hold either.
>
>
More or less it does, for it is questionable whether -addObject should be
>
called a setter and -objectAtIndex should be called a getter ;)
With -objectAtIndex: you are getting information about the array.
With -title you are getting information about the window.
It is an accessor. A collection's data is accessed little piece by little piece, just as a complicated object is accessed little piece by little piece.
Would you prefer if you had
-setItem1:
-setItem2:
-setItem3:
-item1
-item2
-item3
? How would they differ from -objectAtIndex: ? With the ability of Objective C to catch failed messages, examine the name, create a new message, and resend it, the above is very doable.
Should
[myNumericallyIndexedCollection item23]
differ in behavior from
[myNumericallyIndexedCollection objectAtIndex: 23]
or are they both the equivalent accessor?
Now, consider this: The distinction between attribute and relationship. A collection has it's ivars as relationships, not attributes (usually; EOF collections tend to have them as attributes). Maybe the rule is that attributes vended are good for the block, but relationships vended are not.
>
> [more of "things vended from a getter should be good for the block"]
>
Exactly! It follows the expected behavior seen when using [NSString
>
string] or [NSMutableString stringWithCapacity:] (as so on...). I
>
classify them the same as Ondra does and I think it works better and
>
results in cleaner more consistent looking code.
Now hold on a sescond. These routines are explicitly documented as convinience methods for returning an autoreleased object. They are class factory methods, that return an instance of the class -- that's not the same as asking an instance for something about itself.
Now, the [[ivar retain] autorelease] line. I haven't seen the "Here's why" on that mentioned yet, and until I saw MMalcolm's article, I didn't understand it. It's to guarantee to the person calling the getter that the object vended will be valid in the block/autorelease pool of the caller.
But this -- returning autoreleased items guaranteed to be around for a while -- is what convinience creators do, not what accessors do.
I've been using NeXTStep since about 2.3. I've been using openstep since YB/NT (before I programmed against 4.2, actually).
What has changed in Cocoa/10.X that has made this new behavior preferred?
Ali said:
>
(b) nevertheless, accessors should IMHO never vend mutable objects,
>
unless explicitly documented so. That is another thing very worth
>
enlightening in Cocoa; I would advocate though first finish this debate,
>
and then start "when copy" one.
How about this: a setter should never STORE a mutable object? [Again, looking at attribute Ivars, not relationship Ivars. If you have an Ivar that is a relationship, you don't know or care if it's mutable. If you assume that it isn't going to change on you, then it's an attribute.]. EOF insists on it (or did in 4.5, anyways). The very idea of storing a mutable incoming ivar means that data about an object can be changed without the object knowing about it.
Yes, my class might have a mutable Ivar, but it's MY mutable Ivar. I created it, I change it, etc.
I agree -- never vend out an ivar that is mutable -- your object might be changed inconsistently.
Similarly, never take in an ivar that might be muted by someone else.
As MMalcom pointed out, the question of copy/not copy is not something that can be answered in general; it is a per-case decision. As he said, "When trying to determine when to use this approach, bear in mind the difference between attributes and relationships. While this [copy] is appropriate for a Person's name, it may not be appropriate for their spouse..! Ask yourself the question "Do I want the value, or the actual object?" "
Near the end of the discussion, someone asked for a list/names for all the different accessor patterns.
As a first attempt, I give these names (roughly in order of code complexity):
1. Modifiers:
Non-thread safe (multithreaded code needs to co-ordinate this at a higher level)
Thread safe (may be used freely in multithreaded code)
2. Output Base:
Reference vended (caller must retain to use; not thread safe.)
Retain/Autoreleased vended (convinience; guaranteed good to the caller.
If ivar is mutable, caller may or may not see some changes over time.)
Copy/autorelease vended (caller can do whatever they want. Guaranteed good to the caller.
Will not reflect any changes made later to the ivar.)
3. Input base:
Referenced on input, caller must not change (typical for high overhead, or high volume situations)
Referenced on input, changes allowed (Typical for relationship ivars)
Copied on input (Typical for attribute ivars)
Hmm...
Are there really then three perfectly valid different sets of accessors, where different uses of an ivar will give different types of accessors?
Interestingly, and please correct me if I'm wrong, there is no way for the "simple" getter that just returns the ivar pointer to do so in a thread safe way -- without something to increase the reference count (and require an autorelease), before control returns to the caller, another thread can come in and change the data.
In other words, without using that patented autorelease pool, you'd have to explicitly lock the data before you access it. You can't have the lock hidden inside the accessor without having to deal with memory management issues, or leaks, or the pool.
--
I am a Mac OS X-Cocoa/WOF/EOF developer, and I'm available for hire. Please contact me at michael-job @ stb.nccom.com if interested. Resume at
http://resumes.dice.com/keybounce
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.