Re: Memory Management
Re: Memory Management
- Subject: Re: Memory Management
- From: Marcel Weiher <email@hidden>
- Date: Tue, 29 Jul 2003 07:58:43 +0100
On Monday, Jul 28, 2003, at 22:51 Europe/London, Fritz Anderson wrote:
On Monday, 28 July 2003, at 3:12 PM, Marcel Weiher wrote:
On Monday, Jul 28, 2003, at 20:50 Europe/London, Fritz Anderson wrote:
NSString * result = [myNamedObject name];
[myNamedObject release];
NSLog(@"The name was %@" result); // MPW wants an access exception
here.
I don't *want* an access exception here. However an access exception
is perfectly valid here, the code snippet you show is *obviously*
buggy.
You are not allowed to answer that I am _supposed to know_ how -name
is implemented.
EXACTLY, but this is precisely what you are doing when you access the
return value after its containing object is released. The only way
to NOT make this assumption is to retain the result yourself when you
release the container.
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_.
Once again: exactly. You are relying on a particular implementation,
one that autoreleases the object.
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."
You are relying on a particular implementation of the accessor, as
evidenced by the fact that if the accessor is implemented differently,
your code breaks, while mine does not. I rest my case.
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."
False. It requires no such knowledge at all. It requires the caller
to program defensively and *not* assume how the object implements its
methods.
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?
Nothing. As well nothing told me it was not. Therefore, making no
assumptions as to the implementation, I have to assume the worst and
program defensively. This is probably too simple a concept for
advanced OOers like yourself to understand.
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.
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,.
Belief is not a very solid foundation for programming
and one that I had seen violated only once.
Neither is incomplete induction.
I also assume that a class's -description method will return an
NSString *; not all assumptions are unreasonable.
Unlike your (false) assumption about lifetimes, this is not an
assumption:
- (NSString *)description;
is how it is declared in NSObject and every other class. Of course,
you can't rely on that actually being an NSString instance, just
something that will behave like an NSString.
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.
This is also an incorrect assumption.
[snip more personal conjecture]
Personally, I think that's no way to live. Having most simple-object
accessors return [[member retain] autorelease] is a very small price
to pay for very large degree of civilization:
False. It is a very large price ( factor 10 or more) to pay for
virtually no practical payback whatsoever.
The programmer need only consider two classes of memory lifetimes,
autorelease'd and alloc'ed,
Same as with plain retain/release.
and can be certain that anything not returned from alloc/copy/new is
of autorelease lifetime.
And how long is that? Anyway, the issue that you, as well as most
other advocates of autoreleasing accessors so far, are carefully
avoiding is that the autoreleasing accessor only has an "advantage" in
situations where you somehow mess with the containing object. In my
last decade of Cocoa programming, these have been so exceedingly rare
as to be effectively non-existent. So I strongly dispute that this
practice has any measurable *practical* benefit, whereas it has real
and quite measurable cost in terms of performance as well as a cost in
term of program clarity and object semantics.
I will repeat saying that if you have such a situation, then you need
to think carefully about it anyhow in order to get the semantics right,
and adding the retain yourself is actually beneficial in terms of
documenting that something special is happening here.
The third class, for which you have to guess at whether you must be
paranoid (in principle anything not alloc/copy/new), goes away.
You do not have to guess this at all. If you want to keep it, you must
retain it. Anyway, you seem to be making another assumption here:
that deallocating the owner is a common occurrence. It is not. See
the last thread on this subject.
First, the non-retain/autorelease behavior is documented
_extensively._ I'm not religious about [[ retain] autorelease]; if you
want to commit to an implementation in the documentation and warn that
returned values have the recipient's lifetime, you've done you're job.
If you can show your program is spending most of its time in -retain,
or thrashing in an overfull autorelease pool, by all means use a
direct accessor, but document it.
The problem is that this sort of thing is not a hot-spot, but something
that is spread out. Therefore, you cannot easily apply lazy
optimization without fear of having subtly broken something. Anyway,
if you want to use autoreleasing accessors in the privacy of your home,
fine. I only object to it being labeled "standard".
Second, the memory management of the collection classes would be a
better example if it were so blindingly obvious and intuitive that it
didn't _need_ extensive documentation as an difficult case.
I don't see where this is "extensively" documented as a "difficult"
case. For example:
-objectAtIndex:
- (id)objectAtIndex:(unsigned)index
Returns the object located at index. If index is beyond the end of the
array (that is, if index is greater than or equal to the value returned
by count), an NSRangeException is raised.
See Also: - count
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. Such drill (and hours of
trial-and-error) is to be expected for NSArray and NSMutableArray.
This looks like pure conjecture. It certainly wasn't true for me. The
containers work exactly as the "object ownership rules" say, so this
has never been a problem. From what I have seen, it is in fact
"autorelease" semantics that new users have the most difficulties with.
Extending those somewhat difficult semantics across the board does not
sound like a winning proposition to me.
I guarantee you that users will not (should not) forgive that kind of
abuse from less carefully-studied classes beginning with FA, or even
(the excellent) MPW.
(a) it isn't abuse (b) you shouldn't be making guarantees based only on
your assumptions (and several layers of them, too) (c) thank you.
Marcel
--
Marcel Weiher Metaobject Software Technologies
email@hidden www.metaobject.com
Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc.
1d480c25f397c4786386135f8e8938e4
_______________________________________________
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.