Re: cocoa-dev digest, Vol 2 #2711 - 14 msgs
Re: cocoa-dev digest, Vol 2 #2711 - 14 msgs
- Subject: Re: cocoa-dev digest, Vol 2 #2711 - 14 msgs
- From: Chris Purcell <email@hidden>
- Date: Tue, 29 Jul 2003 01:58:30 +0100
You are no stranger to the concept of "object orientation." It allows
us to rely on the behavior and state of programming constructs _without
reference to their implementation_.
In my mind's ear, I hear you saying, in shocked tones, that I am
"access[ing] the return value after its containing object is released."
But that requires one to know that what-name-returns is "contained" (in
some sense which can only boil down to implementation details) and not
"computed." When I said you were not allowed to answer along those
lines, I was restricting you from making implementation-specific
arguments. Who told you that "the return value" of -name _has_ a
"containing object" at all?
I suppose your answer must be that "containing object" is a red
herring, and that -name's return must be retained regardless of how it
might be implemented.
Well, you *are* wanting the name of the object. Expecting that name to
be valid after you've released the object seems perverse. That carries
over to the object's very existence.
When I said I felt entitled to the assumption that returned NSObject
*'s had at least autorelease lifetimes, I was stating what I believed
was a reasonable contract, and one that I had seen violated only once.
I also assume that a class's -description method will return an
NSString *; not all assumptions are unreasonable.
You make a different assumption: That Cocoa memory is a roiling
cauldron of ephemera, and that everything -- including, I suppose, the
results of convenience constructors -- must be nailed down with
-retains immediately, lest they be snatched away in the whirlwind.
Because you have no rigorous way of knowing the "containing object," if
any, of anything, do you? Any -release could bring the whole house of
cards down. I don't think I'm being unfair to you, here: You have
argued that when I send [obj release], objects that depend on obj may
become invalid; I don't think you have a way to stop short of fearing
that _any_ nonretained object may become invalid. O-O principles bar
you from saying what object may or may not depend on another.
This last is nonsense. Let me dissect it.
If an object (A) returns a value (B), you can expect B to be valid
until you alter or release A, regardless of what you do to any other
object not clearly related. (I will come back to this.)
If another object (C) will alter A when it gets a message sent to it,
it is not a principle of O-O that you not know this. O-O prevents you
knowing how an object works internally, not how it affects external
objects.
Try the following:
handlerObject = [myObject handler];
[handlerObject setValue:[anotherObject determineImportantValue]];
If we don't know how object relate - which according to you is not only
plausible but demanded by O-O principles! - this code is invalid in two
ways. The first is that the message to anotherObject may alter
myObject's handler, causing it to be released. Now suppose we fix this
by making -handler return an autoreleased object. This reveals another
flaw with the same root - the message to anotherObject altering
myObject's handler - but a different symptom: since myObject no longer
uses handlerObject, the call to setValue will have no useful effect!
If an object is hidden behind the interface of another object, yes, we
can happily appeal to O-O and claim no knowledge of how it will be
affected. OTOH, we will never actually access that object. As soon as
we get to use them both outside of the cushion of information-hiding,
it becomes vitally important to know how they relate.
Now to return to the validity statement: that B be valid until, and
only until, A is altered or released (which you oppose). The issue here
is what you think the message B is returned from means.
If you see [anObject handler] and think the returned object should be
valid until autorelease time, stop to think what that object actually
is. It is the handler belonging to anObject. It has no relevance
outside of that context, nor should it. It may alter, or it may simply
become invalid. If you want to keep it around for it's own sake, you
should copy it. Note this is not the same concept as retaining it. If
you retain it, it may mutate under you. What you actually want is "the
current handler of anObject, regardless of what then happens to
anObject". That should translate in your code as a copy.
OTOH, if you want to alter that handler, then you shouldn't retain it,
you should take pains to keep it valid. Retaining it simply leaves you
open to the bug I mentioned above.
I would also expect object B could last longer than the current
autorelease cycle. I would expect to be able to pass it safely to other
threads, provided I know that A won't be altered or released in the
meantime (if, say, I'm passing that over, too, or using a semaphore).
The lifetime contract I expect can thus be as long as yours, but
predictably so. There's no voodoo about whether it lasts longer than an
autorelease cycle. It has absolutely no relation to said cycle, in fact.
I don't understand why the behaviour of the collection classes is
treated as somehow abhorrent and evil. Why should you expect "the third
object of array X, at this moment" to be valid once it's no longer in
that array, or when X no longer exists? The only problem is thinking [X
objectAtIndex:3] means anything more than "the third object of array X,
at this moment". That kind of thinking leads people to expect not just
autoreleased objects but thread safety. Programming involves thinking
the right way. In this case, that right way is what you translate
messages as in your head. Yes, retaining objects is a pain, but
treating accessors as:
The third class, for which you have to guess at
whether you must be paranoid (in principle anything not
alloc/copy/new)
is not the solution. Don't be paranoid, just understand what's going
on. It's not like you need to understand anything but the effects of
the code you're writing.
With this in mind:
Who told you that "the return value" of -name _has_ a
"containing object" at all?
The message title did. It means "the name of [object]". If not, choose
a better name. You yourself use this:
I also assume that a class's -description method will return an
NSString *; not all assumptions are unreasonable.
I suppose your answer must be that "containing object" is a red
herring, and that -name's return must be retained regardless of how it
might be implemented.
No. If I saw a method clearly returning an object with an unrelated
lifespan that wouldn't be affected by anything I then do, I wouldn't
worry. For example, [myView superview]. If I don't know the
side-effects of the code I'm about to run, I should find out!
The fact is
that users have to be drilled in a particular mental model of what goes
on in those classes before it becomes "obvious" that the return value
of -objectAtIndex: should be retained if you want to dispose of the
container.
And it's sad that this lesson is not then applied to other cases.
Perhaps those sages who write Cocoa tutorials should do so.
NSString * result = [ofProcessingObject processedString];
[ofProcessObject release];
NSLog(@"The result is %@", result);
I am entitled to assume that result has not been disposed-of, am I not?
Yes. In this case, indubitably. Bad coding in OF, or bad choice of
method name. It translates as "the string that results from
ofProcessingObject's processing", not "the <property> of
ofProcessingObject". I'd say this is the exception that proves the rule.
... but document it.
I agree totally. Document method behaviour. It can't hurt. I also say a
method's zoning behaviour should be documented, and this is in exactly
the same vein.
Kritter out
_______________________________________________
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.