• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: cocoa-dev digest, Vol 2 #2711 - 14 msgs
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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.

  • Follow-Ups:
    • Re: cocoa-dev digest, Vol 2 #2711 - 14 msgs
      • From: Greg Titus <email@hidden>
  • Prev by Date: Making init return a subclass of the Class being init-ed & circular imports
  • Next by Date: Re: Round a float
  • Previous by thread: Re: Making init return a subclass of the Class being init-ed & circular imports
  • Next by thread: Re: cocoa-dev digest, Vol 2 #2711 - 14 msgs
  • Index(es):
    • Date
    • Thread