• 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: Accessors (can we close it this way?)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Accessors (can we close it this way?)


  • Subject: Re: Accessors (can we close it this way?)
  • From: Marco Scheurer <email@hidden>
  • Date: Wed, 7 Aug 2002 17:29:06 +0200

Nice effort to have the last word, but I have to disagree.

On Wednesday, August 7, 2002, at 04:22 pm, Ondra Cada wrote:
Very right. And, in Cocoa with its autorelease pools, unless documentation explicitly says otherwise,

THE VENDOR'S RESPONSIBILITY IS TO ENSURE THAT THE VALUE KEEPS VALID AT LEAST FOR THE SCOPE OF THE CURRENT AUTORELEASE POOL

This is impossible. All it takes is a release from the client to break that pompous statement.

Ah but you're not supposed to release you'll say. Well, that's right: you're not supposed to release your object and then use it without retaining first. That is the advocated usage of retain/release, and has been for years.

I don't want to discuss again and again whether this contract is reasonable (as I think, for good reasons) or irrational (as Marcel thinks,
for perhaps even better reasons, though to me they don't seem such). Nevertheless, in Cocoa, it just is so:

On Wednesday, July 31, 2002, at 07:56 , Ali Ozer wrote:

The API contract for most Cocoa APIs is that the following is valid: (**)

{
str = [someObj title];
... do other stuff ...
... access str ...
}


It's not so yet, and even Ali can make mistakes. Until today, Cocoa documentation says exactly the contrary.

For me, it's another of Cocoa great features. For Marcel, it probably is another of Cocoa design bugs. Any road, it is just so. That does not mean all classes should do so; OTOH, it *does* mean that classes which DO NOT do so *should be documented as such*.

(In current Cocoa frameworks, for historical reasons, they often are not. That is considered a documentation bug and should be eventually fixed.)

I hope not!

The usefulness of this pattern has been grossly exagerated anyway. When people like Georg say that the simple accessor works 95% of the time, they are underestimating, because it is probably more like 99.5% of the time. To prove my point, go through any body of code and count the retain/release or retain/autorelease that had to be written because an operation could have freed an object between the time when it's accessed and the time when it is used.

It happens twice in Sketch, in both case when accessing collection objects,
It happens once in TextEdit, to retain a view from a disposed window
It happens 6 times in Omni's AppKit extension framework for collection related objects, once in another case (because of a removeFromSuperview)

This pattern is almost totally useless.

Furthermore, a client shouldn't have to distinguish between "simple collections" and "complex objects" or whatever else in order to know what to do.

(a) with a simple container, the methods are straighforward. You *do* know that -count or -objectEnumerator won't ever release any of the contained objects.

No kidding? Of course objectEnumerator will not release the object, the problem is with removeObject: and co.

With eg. a window title, though, you *don't* know whether *any* method might not, for some arcane implementation-hidden reason, release the title (and, for example, replace it with another string of the same contents).

Then you have to know what you want to do and code appropriately instead of relying on arbitrary objects staying around just long enough.

(b) with simple containers, we HAVE TO put up with the inconvenient case of "not fulfilling the (**) contract" for efficiency reasons.

It should be emphasized that the difference can be VAST! A benchmark I've rigged up and Marcel considerably improved showed that

- in normal average code, the plain getter (return ivar) can be roughly TEN TIMES slower than the safe one (return [[ivar retain] autorelease]);

That's the other way around of course. Which shows that it is not just useless, but harmful.

Still though there are classes -- in my personal experience, a majority of them! -- usage of whose getters in any sensible design would stay in tens,
at the very worst low hundreds: things like NSTask, NSWindow, NS...Views,
or even the lightweight NSCells. For such classes, I would advocate usage of the safe getter (return [[ivar retain] autorelease]) for either conveniency (should you otherwise go the (a) way below) or safety (should you otherwise go the (b) way below).

It's a bad idea because it's inconsistent. You now have to know, or guess, how your accessor is implemented.

(b) convenient, very often used, but with plain getters inherently unsafe (***)

id o=[foo getter];
... something ...
[o whatever];

This code *MOSTLY* works, I do agree with Marcel that cases when it does not are *RARE*.

That's is not true. The plain getter is simple and cannot be wrong. If something breaks it's the client code. There's no way to protect against all abuse. Or else, why release at all? Keeping everything around is "inherently" safer, at a cost of performance.

You seem to think that "something" is a force of nature, something that you do not control. That's not the case: it is code that YOU write.


The problem is that with complex classes (of foo) you CAN NEVER KNOW in which conditions the problem might occur (and therefore you CAN'T say "here it's safe, no need for (a) patterns"). Not even "not using foo in ...something..." is absolutely safe, for the class just *might*, say, respond to some notification (posted by ...something...) by sending the setter to itself!

Not true in single threaded case, where you know. In the multi threaded case, more is needed anyway. Please stop making this issue so scary and mysterious. This is engineering, not vaudou.

So, the problem is that if you use plain getters with this client pattern,
the application might crash quite unexpectedly eg. with a future bug-fix framework release: the reason would be that you used a wrong code, which would crash only "RARELY". Myself, I prefer code which won't crash -- even if it is somewhat slower.

and possibly wrong, because the crash was a symptom that you were using some obsolete value. Now you can happily use your out of date title without noticing.

Plus, it's not true that the bad code would crash rarely: it would crash pretty often, and should be detected easily. Another way to avoid these cases would be to set pointers to nil when released, everywhere. Messages to nil do not crash, but their effect can generaly be seen quickly enough. Another thing is to use NSZombies.

Marcel advocates that for the consistency sake it should be so with ALL classes. I do agree that it would be consistent; I don't think that would be a good idea though for it would mean we are back in the (a) solution for *any* class, and the inconvenience of it would be (from my subjective point of view) much worse than the gain of the consistency. OTOH, I'd like to point out again that the safe getter can be CONSIDERABLY slower, and thus should not be used if there is a possibility of a really heavy usage.

And I agree with Marcel. And the "safe" getter is an abomination, and should not never be used.

Marco Scheurer
Sen:te, Lausanne, Switzerland http://www.sente.ch
_______________________________________________
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.

References: 
 >Accessors (can we close it this way?) (From: Ondra Cada <email@hidden>)

  • Prev by Date: Re: iTunes programming
  • Next by Date: Re: Accessors (can we close it this way?)
  • Previous by thread: Re: Accessors (can we close it this way?)
  • Next by thread: Re: Accessors (can we close it this way?)
  • Index(es):
    • Date
    • Thread