• 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: Is Apple's singleton sample code correct?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is Apple's singleton sample code correct?


  • Subject: Re: Is Apple's singleton sample code correct?
  • From: Dietmar Planitzer <email@hidden>
  • Date: Sat, 3 Dec 2005 00:24:24 +0100


On Dec 2, 2005, at 7:48 PM, Shaun Wexler wrote:

Yes, there are three obvious bugs, but they aren't in the ref- counting methods. Ref-counting has been REMOVED from the singleton class, so "standard Cocoa" rules don't apply [internally] because the object has become immortal. The sample code is correct.

Shaun, I fear that you have really missed my point. Please go back and read especially the last part of my mail. Then it should be clear to you why I'm against overriding the reference counting methods in the way that the Apple sample code is doing it.

Let's make it short. I have a very simple question for you:

What is the sound and important technical reason for overriding the reference counting methods in the case of a singleton ?

What is the big technical advantage of doing that, especially when compared to the code that I presented in my original mail ? The code in my original mail is able to implement a singleton with a lifetime equal to the lifetime of the application by just overriding 3 methods. That's less than half the number of methods that the Apple code overrides. Considering the famous KISS engineering principle, why should it be better to override more than 6 methods when the same end result can be achieved by overriding just 3 methods ?

I'm sorry but I don't see the point. I've been programming with ObjC for more than 10 years now (seems like that mentioning such private information is somehow considered important..) and I've never had any reason to override -retain, -release or -autorelease in all that time so that they do nothing. Neither in the case of a regular object nor in the case of a singleton.

The first bug is that if -dealloc is sent to it directly, it will be freed, so -dealloc must be overridden to become a NOP, ala - release. That method should be added to the sample code.

Could you please give me a sound technical reason why overriding - dealloc in the case of a singleton so that it does nothing is supposed to be a good idea ?

I personally think that it is not only unnecessary and that it needlessly complicates the code base, but I also think that it makes it unnecessarily harder to find a memory management bug in the code that is using the singleton.

The reason why I think that doing this is not a good idea is that code which calls a -dealloc method directly, no matter on what object, severely violates the CMM rules. Thus, I should be able to find this problem efficiently and in short order. But overriding - dealloc so that it does nothing makes it unnecessarily hard for me to find this problem as it gets swept under the rug. At least, when you really want to write your code that way, make sure that dealloc raises an appropriate exception so that we get a chance at fixing code that is using the singleton in an inappropriate way.

The second bug is that the recursive mutex @synchronized(self) needs to be @synchronized([MyGizmoClass class]) in both class methods, because the static variable sharedGizmoManager is what the mutex has to protect, because two subclasses created simultaneously on two threads permits a race situation. The sample code should be updated and documented to reflect this.

Well, I think that the sample code should concentrate on the core issue of writing a singleton. I don't think that it's such a good idea that it drags side issues like multi threading in which has nothing to do with the general and basic question of how a singleton is typically implemented in the case of Cocoa. It needlessly complicates the sample code and distracts from the actual problem. This is in fact the reason why I have dropped the thread-safety stuff altogether in my code. It just distracts.

The third bug is that the design is messy, and doesn't allow subclassing. Both +sharedManager and +allocWithZone: allow assignment of sharedGizmoManager, and it reassigns it (and hits the lock twice) when instantiated properly. According to the last comment, this is intended to permit optional usage. The sample code should be augmented with 2 or 3 other singleton designs, with examples. Also, the +sharedManager methods should be more efficient because they are messaged often, and entering the mutex should be avoided if the static var is valid, plus an early exit minimizes the cache hits to load the unnecessary code each use.

+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager) {
return sharedGizmoManager;
}

@synchronized(self) {
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[self alloc] init];
}
}
return sharedGizmoManager;
}

Hmm, please give me a sound technical explanation why you think that the double-check locking idiom works reliably in ObjC. I'm asking you because I know that it does not work reliably in Java, C and C++ and I can't remember that Apple has refined the definition of the ObjC language so that it gives any guarantee with regards to the order in which the compiler generates instructions for a nested message send expression. Nor do I remember that the language gives any guarantee about the exact time when a value is written from a register to a global variable.

Therefor, I'm interested in whether Apple has indeed changed the language in such a way that the idiom above is guaranteed to work.

Now, I do know that there are quite a bunch of changes to the runtime waiting in the wings. If you want to know more about this, then simply head over to the GCC SVN repository and check out the ObjC related parts of the GCC compiler in the Apple branch. There's a lot of very interesting stuff to be found there, if you dig deep enough.

Readers who don't yet know what the double-check locking idiom is may simply enter that phrase in Google. You'll get tons of documents that describe what it is and why it does not work in the "standard" programming languages.

The short explanation is that:

1) Thread #1 calls +sharedManager, sees that the singleton doesn't exist yet, enters the synchronized block, calls +alloc and writes the result back to the variable sharedGizmoManager.

2) Now a context switch happens from Thread #1 to Thread #2.

3) Thread #2 calls +sharedManager and by executing the first if statement sees that the singleton does already exists.

4) Thread #2 now happily goes on to use the singleton, which however has not yet been initialized by Thread #1 because the OS scheduler decided to demote it from running state to ready state...

Really, this thread is entirely too silly, but with all of the C++/ WIN switchers to come, it's better to explain it correctly in the archives, or we'll have to go thru it again and again.

Honestly I don't know why you call this thread entirely too silly. The only problem that I see with this thread is that at the beginning there was a very simple question. However, although a lot has been said in this thread, and a lot of topics have been brought up that have absolutely nothing to do with the original question, so far nobody has given a simple, clear and sound technical explanation why it is necessary to override the reference counting methods. Note that I said, necessary. Since quite a number of people have sided with the Apple sample code, I have to assume that there must be a really important reason that it overrides -retain, -release and -autorelease and that by doing so it achieves something really important that would not be achievable by implementing the singleton using the standard CMM rules like I did in my code.

So please, could someone answer this simple question : What is the seemingly so important advantage of overriding the reference counting methods ?

Or formulated in a different way: why should the implementation of a singleton not follow the standard CMM rules ?

And just to make it clear: I'm not going to accept answers like, it makes ref counting faster or it makes it possible to violate the CMM rules in the implementation of the singleton's +alloc and -copy methods, or that is how NeXT did it. I'm sorry, but those are not sound technical reasons for me.


Regards,

Dietmar Planitzer

_______________________________________________
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
  • Follow-Ups:
    • Re: Is Apple's singleton sample code correct?
      • From: Shaun Wexler <email@hidden>
References: 
 >RE: Is Apple's singleton sample code correct? (From: Jeff Laing <email@hidden>)
 >Re: Is Apple's singleton sample code correct? (From: mmalcolm crawford <email@hidden>)
 >Re: Is Apple's singleton sample code correct? (From: Dietmar Planitzer <email@hidden>)
 >Re: Is Apple's singleton sample code correct? (From: Shaun Wexler <email@hidden>)

  • Prev by Date: Reducer Tutorial leak?
  • Next by Date: Re: What is the best way to use NSOutlineView without NSTreeController?
  • Previous by thread: Re: Is Apple's singleton sample code correct?
  • Next by thread: Re: Is Apple's singleton sample code correct?
  • Index(es):
    • Date
    • Thread