Re: Is Apple's singleton sample code correct?
Re: Is Apple's singleton sample code correct?
- Subject: Re: Is Apple's singleton sample code correct?
- From: David Gimeno Gost <email@hidden>
- Date: Sat, 3 Dec 2005 01:47:00 +0100
On 2 Dec 2005, at 07:58, mmalcolm crawford wrote:
It's not clear why this:
[...]
would be a solution, since dealloc is never called.
Because the problem (one of the problems) is not that -dealloc should
be called. The problem is that -dealloc shouldn't be prevented from
ever being called.
If preventing -dealloc from ever being called simplified the code and
made it more understandable for novices, I would have understood it and
would have stopped there. But that's not the case, actually it's the
other way around.
allows premature deallocation,
I suspect I don't fully understand this requirement then. I thought
that its rationale was that we wanted to avoid expensive (full)
re-instantiation, which never happens in this case because the instance
that gets discarded is never initialized (which I thought was the
expensive part).
Is it really a problem the extra (non-initialized) allocation in the
(very unlikely) case that [[MySingleton alloc] init] is ever called? I
believe that avoidance of the repeated -init invocation problem
outweighs this requirement by far, doesn't it?
It remains unclear how you intend to ensure that the singleton is
deallocated only when it is guaranteed not to be needed again.
It is automatically ensured by just requiring client code to follow
the memory management rules.
Given that the in implementation you propose above dealloc is not
called, the solution remains unclear.
I realize there has been another misunderstanding here. I'm not trying
to ensure that the singleton is ever deallocated under any
circumstances (see below).
*dealloc should _not_ be used as the locus of code for doing general
resource reclamation.* Other current threads have indicated why
this might be the case (see, for example,
<http://lists.apple.com/archives/Cocoa-dev/2005/Nov/msg02113.html>).
Actually, I already had this in mind and considered it a reason to
use -dealloc for resource deallocation until garbage collection
becomes available. Let me elaborate:
We cannot think of -finalize as a -doCleanUp method, because what
really makes it special is that it will be _automagically_ called
when the garbage collector determines that no other object keeps a
reference to the instance. The closest we can get to this behavior
without GC is to rely on -dealloc being called when all retained
references to the object are released. This would make it easier to
modify the code to take advantage of garbage collection when it
becomes available, wouldn't it?
This is wrong. (I can't elaborate.)
I believe that I'm starting to understand this now, but I'll leave that
for another thread. Talking about this here would just add more
confusion.
Let me know if you believe the above implementation fails to satisfy
any of those requirements.
dealloc is not invoked.
Nor should it be. It should just not be prevented from ever being
invoked.
Let's suppose that, for whatever reasons, we want to modify our
singleton such that it can safely be used like this:
[MySingleton releaseSharedInstance];
Since we haven't prevented -dealloc from ever being called, we can
modify our generic singleton class as follows:
static MySingleton* sSharedInstance = nil;
static BOOL sCanBeReleased = NO;
+ (MySingleton*) sharedInstance
{
@synchronized( self ) {
if ( sSharedInstance == nil ) {
// Note: calls -singletonInit instead of -init
sSharedInstance = [[MySingleton alloc] singletonInit];
sCanBeReleased = YES;
}
}
return sSharedInstance;
}
+ (void) releaseSharedInstance
{
@synchronized( self ) {
if ( sCanBeReleased ) {
[sSharedInstance release];
sCanBeReleased = NO;
}
}
}
- (void) dealloc
{
sSharedInstance = nil;
}
Note: I'm not saying that people should do this, nor that it is the
best way of doing it, nor that -dealloc should be invoked in the
general case. I'm just saying that -dealloc shouldn't be prevented from
ever being invoked unless there is a trade-off that justifies such
constraint.
I don't see it as being any easier to understand than the current
implementation -- in particular:
- (id) init
{
[self release];
this is certainly not going to make it easier for a novice...
It makes explicit the trick that ensures the uniqueness of the
singleton when it's instantiated via alloc/init. Note also that the
possibility of calling [self release] is already documented in Cocoa's
design guidelines for object creation:
http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaObjects/
Articles/ObjectCreation.html#//apple_ref/doc/uid/20002154-1006261
If you think this is hard to understand for a novice (I'm not saying it
isn't), then that document should be revised to explain what "Release
the newly allocated object" means, and it shouldn't be a reason to
reject that implementation any more.
On the other hand, the current Apple's singleton sample code obfuscates
what's really going on behind the scenes, and the novice isn't even
aware that he/she doesn't really understand it. Moreover, he/she can be
really confused by the breakage of the ownership contract and gets the
feeling that there's something about the memory management rules he/she
doesn't understand.
It'd be interesting to try this: ask a novice which of the two
implementations is easier to understand, and then tell him/her to
describe what that implementation does.
Regards.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden