Simpleton Pattern Discussion

From SimpletonPattern:

I think epithet of "simpleton" rather applies to the content of this article, if not to its author. The argumentation smacks as handwaving and has failed to even attempt to convince me - it's arguing from a set of assumptions and possibly prejudices that are not even made explicit, but the reader is expected to guess what those are and buy into them. -- CostinCozianu

Did SingletonsAreEvil convince you? For me ItDepends. If you need the context (for testing, configuration, whatever, then singletons are problematic, if you don't (e.g. simple applet) they are easy. --.gz

[Original Author] Uh. QED, I think. Line three is a Syllogism. See http://en.wikipedia.org/wiki/Syllogism

I quote from opening sentence of the source above "Syllogisms are the cornerstone of the logical tradition..."

I took a course in formal logic in University. I presume most (or at least many) of the readers of this site did as well. You may see for yourself that the syllogism is correctly formed. I really do believe that a correctly formed syllogism would be a little more than mere 'handwaving' as far as an argument goes.

One could could hardly fault the logic. One might quibble with the two premises, but that is rather difficult.

Premise 1: Globals are bad. I believe that the fact that globals are to be avoided is pretty much a finished argument in the literate programming community. See some straightforward quotes from others below. The admonition against the use of globals is actually a special case of a 'best practices' scoping principle. Things should have the smallest scope required to do their job. As an aside, one generally decreases the size of a variable name as scope decreases. The wider the scope, the longer and more descriptive the variable name. I am not teaching programming here. I will simply state that there are many problems with globals and they should be avoided. If you disagree with this premise, then you disagree with the argument. We will have to agree to disagree.

Premise 2: Singletons are globals. Uh. I am not sure what to say here. Would they not be global (for these purposes) of necessity? I assert that Premise 2 is correct. If you disagree, let me know and I will dig up reference for that as well.

So: I have stated a valid formal logical argument (Syllogism). If its premises are sound, the argument is sound. I have stated a major premise that a category of objects (globals) necessarily has some characteristic ('are bad'). I have stated a minor premise that a particular thing is a member of the above category. The argument is well-formed and sound as far as I can see and it is based on 'true' premises.

Name-calling ('simpleton, 'the author'), etc. is not a valid logical argument. I am not sure if it falls into the category of 'ad hominum' attack, 'appeal to the mob' or 'straw man'. Perhaps it is a member of all three.

A few opinions from others on the use of global variables.

From: http://www.digitalmars.com/archives/cplusplus/1087.html 1) Global variables don't work well with multithreaded program, and are almost always a subtle bug. The trouble comes if two threads try to access a single global at the same time.

2) Any function can read/write globals, which means that in a large program, it becomes hard to follow the logic of who reads the globals and who writes them.

From: http://www.samspublishing.com/articles/article.asp?p=31668&rl=1

Avoid Using Global Variables

Unless it is absolutely necessary, don't use global variables in your code. Apart from polluting the global namespace (and increasing the chance of a name collision), it increases the dependencies between translation units that use the variables. This makes code difficult to maintain and minimizes the ease with which translation units can be used in other programs. The fact that variables are declared elsewhere also makes code difficult to understand.

http://www.miislita.com/searchito/javascript-optimization.html One of the "great offenders"! Whenever possible, avoid global variables. Use the var keyword to declare them as local. Local variables are searched first and run faster than global variables. Also precache chain lookups. Scope chain lookups inside loops are time consuming. Avoid whitespace and comments inside loops. These practices are common "speed offender", found in many online scripts, favelets (bookmarklets) and even in many JavaScript books.

From: http://www.stevemcconnell.com/ieeesoftware/bp06.htm

Global data. The existence of global data introduces the possibility that virtually any part of a program can interact with any other part of a program through their operations on the same data. The use of even a few global variables dramatically increases the complexity that a human reader has to deal with when trying to understand a program, and for that reason use of global data compromises the programmer's primary objective of keeping complexity to a minimum.

Gee, if you took a course in formal logic, you'd know that logic is a formal language, while what you have here is rather cheap rhetoric - a rather staggering difference. I am not aware of any formalization of cheap rhetoric that puts it on par with formal logic.

''Re the above -- You are falling prey to what I think of as an example of an 'off by one' error. You have confused levels of abstraction. Logic is logic. Formal Languages are formal languages. Logical FORMS are often expressed in many ways. You (I think) make reference to something like a syllogistic form:

That is the description - a 'class', if you will, of syllogisms. What I provided was an actual syllogism - an instance in this metaphor. I would like to say something pithy about this poignant moment, but Wittgenstein (http://www.iep.utm.edu/w/wittgens.htm) has beaten me to it:

"...what is the use of studying philosophy if all that it does for you is enable you to talk with some plausibility about some abstruse questions of logic, etc., and it does not improve your thinking about the important everyday questions of life."

To begin with, you, yourself made the argument very personal by the style of rhetoric you used, by the fact that you CriticizeBluntly presumably a large body of practice, using unnecessary harsh words, while shying away from the responsibility of your own words (do you mind to sign, and if you are new to wiki, which it looks like, present something of a HomePage, so that we can know your background, where you came from, what assumptions/prejudices you seem to hold dear, etc ?), and in the same time appealing to personal trust with expression like "believe me", the voice of the teacher ("I") speaking to students ("you"), like in "you have no business", presuming any argument to the contrary to be made from ignorance and so on, so forth ... What does it mean "believe me", when the guy who says it is in AnonymousCoward role. There's no way you're going to be believable from that position. So GetOverIt, you live by the sword, you die by the sword. If your rhetoric would have displayed humility, the "acute awareness of the limited size of your own skull", and some level of accountability, I myself wouldn't have had reason to truly believe that I am witnessing a form of handwaving masquerading as "logic", and even if I believed it, I wouldn't have said it.

''Merciful heavens (that *is* rhetoric, I suppose). Were I a kettle, I would swear you were a pot. For the most part, what I said was (harshness alert was given) well defended in and of itself. Do you need to have a personal relationship with every single entity on the Internet to bother reading what they say and using your own brain to assess its validity? The 'new to wiki' shot is yet another gratuitous 'ad hominum' swipe. In fact, I have used wikis for years. I have a few on the Internet, have contributed to a number (I'm not sure if this ascending flame war would count) and even though they have fallen out of favor with me, I actually have three live ones on my own local network. By co-incidence, I just installed mediawiki on my own local server on Friday. As a matter of fact, one of my bug-fixes is in CVS for one of the most popular wikis on the Internet. Your powers of divination leave something to be desired... As for a home page -- I have two entirely personal domains and I do have a home page on another wiki that is years old. I really don't need any more links to moi, thanks for asking.

'' With respect to your: 'presumably a large body of practice', all I can say is you need to get some knowledge of logical argument under your belt. Everyone in the world once believed the sun revolved around the earth. It had little influence on the sun. BTW -- do you even know what 'handwaving' means? Also, why on earth would you quote the word "logic". I am certain you can look up syllogism on the Internet from some place you trust. Beyond understanding how it works, I have provided the rest of the material on this page. I presume you have something to do with programming and unless I missed a meeting, logic is sort of a crucial aspect to our line of work. You needn't learn the latin, but you should be able to deal with a truth table, etc.

Now, setting aside the cheap rhetoric, and going to the heart of the matter. Singletons are not global variables by definition; if they were, we wouldn't have used a different word. Therefore we have to assume that there are similarities and differences between singletons and global variables, so you have to establish those, and you have to establish that the very reason that global variables are considered bad are applicable to singletons, and that the differences between the two concepts don't make a difference in the "singletons are bad" argument. That would be a proper argument. Oh, some edifying examples in code would be nice as well. With no code to support it, absolutely no argument about programming matters is worthy of consideration. Think of some typical uses of the SingletonPattern that everybody (or a large number of WikiReaders) should be familiar with, and show us what you think they should be replaced with. And then we have some meat to argue about. And before you contemplate thinking the construction of that argument consider the following truly global singleton that everybody and their grandma (most likely including you) use day by day in their programming tasks. Those would be 0, 1, 2 . Do these numbers ring any bell to you? -- CostinCozianu

''I am really getting stumped. Is this a joke? Are you just flaming for the heck of it? Both Apples and Oranges are fruit. Both Singletons and Global variables are global - geddit? I am not objecting to your beloved Apple's 'Appleness'. I am objecting to its 'Fruitness'. Global bad.

You say "some edifying examples in code would be nice as well. With no code to support it...blah, blah". You assert the Easter Bunny is real. I assert that he is not. It is up to you to produce the Easter Bunny, not I. Similarly, you want me to produce examples of where it is presumably necessary? I'm beat. How about you? Are you attempting to assert that it is not possible to produce code without cross-scope access to things? I could hardly dignify that. Anyone who needed code for that would not understand it anyway. I think this might be another break-down in levels of abstraction. What the language provides me (say stdio.h) is a black box. In C, for instance, I get the language in the global name space (go figure). Beyond that, I get argc and argv and I proceed from main(). I can pass context down from there with nary a global in sight. I think I gave some rather concrete examples up front of the types of objects BIOS, etc. Here's a quote from the GOF book: "An accounting system will be dedicated to serving one company" [P.127 where they define singleton]. I think that sentence is silly on the face of it, but even if it were true, there would be no utility in enforcing that opinion in code. I only see downside there.

I have rather dealt with the 'not global variables' at length in ForThisPurposeSingletonsAreGlobals. I would respectfully suggest that you do not quite understand scoping issues at the very least. At the risk of being a poor citizen, I will excerpt a couple of lines from that page:

"In the book that presumably influenced this wiki, the definition of a Singleton is simple and unambiguous. It so happens that I came to this site while I was reading the book. It's on my desk right now and it is open to page 127 (sixth printing, April 1996). Here is what it says: Singleton -- Object Creational Intent Ensure a class only has one instance, and provide a global point of access to it."

Perhaps that is not the canonical definition of a Singleton, but I can tell you that a big chunk of the Internet is running with that. Anyway, this is an issue of semantics. Whatever language you use and whatever definition you use at the end of the day you are defending something quite hopeless. It is a failed concept. Deal with it. ---

What's the deal with the counting numbers? Are you telling me there exists a code example somewhere where they are all coded as Singletons? This has to be a joke. Anyway, my grandparents are no longer living. Thanks for mentioning it.


But... I'm not sure that a singleton is necessarily a global, for any specific meaning of "global". --RobertFisher

[Original Author (described as AnonymousCoward above). So be it. Anyone that is really curious can FindMeEasilyEnough?.]

Note that I said above ForThisPurposeSingletonsAreGlobals. I am happy enough to stand by that. If you follow the link there, you will see a mountain of links and references that mention Singletons as having the following properties:

1) Ensure a class has a single instance. 2) Provide a GLOBAL point of access to the above.

Both of the above properties are (IMNHO) journeyman mistakes at best. I would say that anyone with less than about 10 thousand solid hours of heads-down coding is basically a journeyman. I have more than that (I started coding in 1976). I'm still learning. I would say that there is little for me to learn from the above. Note that I said "except as a sloppy 'stopgap' while you attempt to fix your broken (or forming) context structure" above. I wanted to add that I DO in fact use things with global scope and presumptive singularity from time to time during development. I just had so much stuff there I did not want to bog it down any further. There is a lot of ugly scaffolding involved in putting up a nice piece of work. I try not to confuse the scaffolding I am using with the object I am using it to build. The scaffolding comes down when the work is done.

What I am saying (I hope pretty loud and clear) is that these are (to put it mildly) not 'best practices':

  1. Something that locks you into an unnecessary presumption (there can be only one) and
  2. Allows information (or worse: control) to 'bleed' to places it is not needed

In the real world, enterprise software running international telecommunication networks, banking, insurance, etc is much larger than the 'toy' examples that are used to defend the use of things like a singleton pattern. It is also much older. It also is expected to last a lot longer. Some of it is amortized over horizons like 30 years. I kid you not. Truly global access within software is a showstopper. Moving beyond scope is not far behind. Consider this: A big system has an enormous global scope. Assuming that there is necessarily a single instance of something and that this will remain the case forever across the system and whatever happens to the code when your tenure lapses is presumptuous in the extreme.

Non-trivial software fails. Of that you can be certain. It does not matter how good you are, how hard you try or how long you work at it. Software fails. As a programmer, one of your tasks is to minimize that failure as much as you can. Singletons are an unnecessary source of failure by their fundamental nature. You might be able to do a torturous work-around on a small system, but you will never be able to 'beat the system' on a real system. If you use things that have the characteristics of Singletons, you will have bugs. They will be big. They will be nasty. They will be very, very hard to find. That is particularly true if you continue to hold to the foolhardy notion that things that have unnecessary global scope and behavioral assumptions are just dandy. I see globals or wacky assumptions in code and they look like sand from an anthill. I may not be able to see the ants, but I know they are there.

Please do consider from your lofty height the following: What makes you (or anybody) so sure that something actually is a singleton (by nature)? That is, how can you possibly prove that you will only ever need a single instance of that thing? That your imagination fails to see how two computers the same program would ever share is hardly an argument in favor of chaining your customer to that assumption until the end of time. If you are wrong, somebody will either have to live with broken code or pay extra money to fix it (if it can even be done). Why take the chance?

We can code my way and if there only remains one (insert example you never supplied that is necessarily a singleton) then the code will not break. If it turns out that people DO actually run multiple operating systems across our code and there becomes more than one the code will not break.

If we code your way and there remains only one, we're golden. If there turns out to be more than one, our code will break.

At this point, I think I should mention that Murphy's Law is not a joke. It is a force of nature, just like gravity. If you allow anything to go wrong, then it will go wrong in the fullness of time. I confess that I have learned that lesson more than one time the hard way myself.

I said at the outset that it was going to be harsh. I do apologize for the tone. I knew it would be a bit contentious. However, this is serious business. A single error can destroy an entire system involving literally hundreds of man-years worth of work. This is a hygiene issue. If you are arguing in favor of using Singletons on purpose, you are putting not only your own work at risk, but the work of many others as well. As my old Biology professor said apropos of Creationism Vs Evolution: "It is a matter of knowledge, not opinion".

As for 'code examples', who are you, etc, etc. Goodness gracious me. There is either a reading comprehension problem here or an enormous gap in general knowledge. The words speak for themselves. I have an IQ two or three standard deviations above normal. However, that has no more to do with the arguments than if I were, in fact, a simpleton. Here is a discussion on IQ (such as it goes) http://en.wikipedia.org/wiki/IQ. My esteemed colleague who implied that I might be a simpleton above might well read very carefully on this subject. If he looks at the figures he will see that there is a finite probability that I may technically exceed his intelligence (such as these measures go!) by the same amount that he exceeds the intelligence of a 'moron'. Note that this is by the archaic scale that matches his 'simpleton' (synonym for moron) nomenclature. The standard error of measurement for IQ tests (if I recall correctly) is about half a standard deviation. One standard deviation on modern IQ tests is 15 points and average (one hopes you know this) is 100.

My wife is actually a real psychologist who measures IQ routinely. Neither of us has much faith in IQ measurements beyond their diagnostic utility. I mention all of these merely to drive home the point that my presumptive lack of brainpower is entirely irrelevant to whether or not the words I wrote are logical, coherent and have merit.

The 'who are you' thing is (possibly) going down the slippery slope of yet another logical fallacy: ipse dixit. If my arguments and evidence are not sound in and of themselves, my upstanding nature will not help them. The same rules apply to us all, I am afraid.

Hardly any arguments can be made out of context. A person that can be known provides much of the context needed to understand an argument. Hardly any person is talented enough to present an argument so that it doesn't require any contextual information. I'm not concerned about your IQ, I'm concerned about your style and your way of constructing arguments, they're just lame.

[EditHint: ditch the 'ScareQuotes?']


Can we return to the original premise of this page?

Anyway, either the logical argument above is not a syllogism, or one of the premises is false. If you want to argue that it's a syllogism, it needs to have the form:
  1. All global variables are bad
  2. All singletons are global variables
  3. Therefore, all singletons are bad
Premise 2 is not really in dispute, because a simple syntactic transformation can convert from a singleton to a global variable (module locking/threadsafety). However, you're misunderstanding most of the references you cite if you believe they say all global variables are bad. ThereAreNoAbsolutes? in programming (well, I suppose you could argue "Always double-check control systems for nuclear warheads" is an absolute, but that's off-topic). Experienced programmers know when to break prohibitions against global variables or GoTo statements, and they also know that those occasions are far more rare than most programmers think. When experts say "global variables are bad", they mean "most global variables are bad".

That said, I've found that SingletonsAreEvil far more often than not. The problems aren't so much that they're global variables as that they're not global variables. I do a lot of DistributedProgramming work, and singletons/globals really mean "1 per process". This becomes utterly useless when your software is spread throughout a multi-machine cluster.

Costin, as for what to do instead: pass it as a parameter, or create a single service registry that all clients must communicate with via MessagePassing. The exact strategy depends on the problem. Network and database connections should be passed around: they're almost never really singletons, regardless of how much you think so, and you inevitably want to communicate with 2 servers from one process. Print spoolers etc. should also be represented by a connection object that's passed around: what happens when you get multiple printers? Logging should be handled as a service, located on a single machine, that you send messages to when you want to log something. The singleton approach becomes a huge mess in a distributed environment, with separate log files on each machine. MonadicProgramming is another approach if the language supports it: it's equivalent to passing parameters around, but hides the nitty-gritty details so you don't have to add it to every function on the call graph.

BTW, IQ arguments are tacky. I know of at least 3 people on this Wiki with IQs over *4* standard deviations above normal, and at least 2 with IQs *5* standard deviations above normal. No matter how high it is, there's always someone higher. -- JonathanTang

Runtime.getDefault() is about as close as you can get to something that should legitimately be a singleton, because it deals with operations that logically should be one-per-VM. Nevertheless, I would still revise it to use a Netbeans/Jini-style Lookup service. Here's why: Note that said Lookup service is itself a singleton. I never said they were all bad, only that they were mostly bad. The point of a local Lookup object is to register the services that are available in the local VM; therefore, it needs a mechanism to ensure that there is only one Lookup object on the local VM.

Toolkit.getDefaultToolkit() is used to provide factory implementations for the various AWT classes, because the AWT relies on native C APIs. The refactoring I'd suggest has already been performed: it's called Swing. Much of the functionality in Toolkit is either passed around with the Swing objects (their UI implementations & event listeners) or simply not needed.

Much of the remainder has subtle problems that I don't know if Java has an answer for: -- JonathanTang

Your what if argumentation is entirely invalid because the overwhelming majority of cases are not concerned with your "what ifs", therefore they do not need to pay for the increase complexity for your what ifs. If you are really concerned about the "whatifs" above, you're free to set up your own alternative mechanism and pay for the increased complexity yourself. As a matter of fact, nobody prevents you from adding a layer of indirection to Runtime.getRuntime() and the likes. -- CostinCozianu


I don't want to get too involved in this discussion (too hostile for my tastes), but I thought I'd offer up this definition of "global" for consideration. Global means any object that can be accessed by a function, when that object is not reachable, directly or indirectly, from the function's parameters, including the implicit "this" parameter. -- MichaelSparks


Perhaps Some More Concrete Definitions Would Help

I believe in the context of "Globals are Bad" the term is short for "Global Variables." A singleton, however, is a "Global Object" comprised of methods and, optionally, variables. The argument against global variables is largely one of coupling, the amount of "distance" between a variable and the methods that use it. With a global variable, the methods that act on the variable are scattered throughout the source code, making consistent and correct use of the variable extremely difficult. With a singleton, the methods that operate on the variable are colocated, making it much easier to ensure consistent and correct manipulation of the variable.

Singletons are not global variables. The arguments against global variables do not apply to singletons.

Hmm, I'd say that global X (whether variable, object, class, whatever) means, that X is reachable transitively from an implied 'parameter' called "global" by convention. This 'parameter' is usually realized by your compiler and provided by your execution environment (e.g. in the form of memory accessible from the code).

Examples:

Global variables (as e.g. in C): The implied variable "global" refers to the symbol table of the current object file. From there the 'global' variables are looked up by name (this is done statically by the linker, i.e. the 'actual' references are erased from the binary).

Singletons (as in Java): The implied variable "global" refers to the current ClassLoader (which you can actually get from each Objects class). The singletons (or in fact any class) are referenced by name (the fully qualified class name incl. package, this is a String, though it looks like a path in a tree, which it isn't).

-- GunnarZarncke (and I agree, that this discussion has a much too hostile tone)

Perhaps we can define the "globalness" of a Global Variable and of a Singleton as follows:

A Global Variable is a data storage area that is in scope for direct access by any line of code in a single executable module.

A Singleton is a set of methods that may be in scope for direct access by any line of code in a single executable module. The Singleton may contain data storage areas that are only in scope for direct access by lines of code in the singleton.

[Yeah, this wording seems a little clumsy. Feel free to update for clarity.]

Given an acceptable set of definitions, perhaps a discussion of the implications of "globalness" for both Global Variables and Singletons can ensue.

What is wrong with a global DEBUG constant (used often by the pre-processor)? What is wrong with a singleton O/S-level message queue or interrupt queue?
Examples of singletons that aren't evil needed? OK, here's one. How about an application-wide cache, such as a Web browser might use? We'd have a) a non-singleton, non-global method of getting foos (html pages, whatever) and b) a singleton cache with generic methods to take a foofactory bound to its parameters and produce a foo. The latter has a hashmap under the hood that looks up the bound-factory object as key. If there's something stored for that key it's returned. If there's nothing there, the foofactory is invoked to generate the foo, which is stored in the map and also returned.

This would be for efficiency where getting the foo from the bound factory instance is expensive. An example foo factory would be an object that can be constructed with a URL and then invoked to produce an input stream for the Web page from that URL. The cache may actually return an input stream from a disk file or from a memory buffer, rather than the network, and the client code is agnostic as to which of the three it is. For maximum efficiency the cache object should be a singleton. Its encapsulation barrier hides the global state (the hashmap) and provides a logically-constant semantics to the outside world, and also localizes in one place the caching logic such as expiring cache entries and so forth. Making the cache use the disk as well as memory is a change localizable in one place in the code.

In the example just given, the singleton acts semantically as a global constant -- and it actually is an alternative to global variables (e.g. a global hashmap) or a context object (passing the hashmap around everywhere, alone or curried).


How about the singletons 0,1,2

These are not singletons - '1' in one place is not necessarily the same object as a '1' in another. The fact that they may be indistinguishable is irrelevant, the singleton pattern is about enforcing the rule that only one is ever created which is clearly not the case. Literal constants don't have the problems associated with global variables because they are not variables; there is no problem with global (immutable) constants.

Those are flyweights, you fool!


DeleteThisPageSomeTime

CategoryDiscussion

EditText of this page (last edited April 3, 2010) or FindPage with title or text search