Accessors (can we close it this way?)
Accessors (can we close it this way?)
- Subject: Accessors (can we close it this way?)
- From: Ondra Cada <email@hidden>
- Date: Wed, 7 Aug 2002 16:22:11 +0200
First, anybody who feels he does not fully understand the issue, do please
read the article
http://www.stepwise.com/Articles/Technical/2002-06-11.01.html
It explains all the details in a much more intelligible way than this
discussion (well, the facts are almost identical, but the article is
didactic, whilst the thread is chatoic ;)
On Wednesday, August 7, 2002, at 12:00 , Marcel Weiher wrote:
I am glad you brought this up: for a client, wether something is an
accessor or not does not and should not matter. For a client, it is just
a method that returns a value.
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
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 ...
}
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.)
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. 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).
(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]);
- if clients use IMP-based optimization, the difference can go up to FORTY
FIVE TIMES!
Therefore, you should definitely consider the usage patterns; if there is
probability of thousands or more getter accesses in succession, clients
just have to put up with the plain getter (for otherwise the speed penalty
would be too big).
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).
(In current Cocoa, for historical reasons, these classes often don't use
the safe getters. That is considered an implementation bug and should be
eventually fixed. Some such cases were fixed already in Jaguar.)
Just follow the ownership rules and you'll be fine.
You WON'T, for the reasons stated below, (***). There are only two things
you can do
(a) safe but quite inconvenient if used any time for any getter of any
class
EVERYTIME use one of these four patterns:
id o=[foo getter];
// NO CODE HERE!!!!
[o whatever];
// o NEVER MORE USED
id o=[[[foo getter] retain] autorelease];
// all right here, for you precisely repeated what should have been done
in the getter
id o=[[foo getter] retain];
// code you are sure won't raise
[o whatever]; // whatever can't raise either
[o release];
id o=[[foo getter] retain];
NS_DURING
// code which might raise (almost any nontrivial code in Cocoa!)
[o whatever];
[o release];
NS_HANDLER
[o release];
[localException raise];
NS_ENDHANDLER
(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*.
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!
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.
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.
---
Ondra Cada
OCSoftware: email@hidden
http://www.ocs.cz
private email@hidden
http://www.ocs.cz/oc
_______________________________________________
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.