So Alex doesn't like the Singleton pattern.

Alex Martelli aleaxit at yahoo.com
Fri Apr 20 09:34:28 EDT 2001


"Laura Creighton" <lac at cd.chalmers.se> wrote in message
news:mailman.987763024.10421.python-list at python.org...
> Why?
>
> I thought the only reason to get out flyweight was because your program
> was a turtle

"Turtle"?  You mean as in "sea turtle" or as in "turtle dove"?
In either case, I must be missing some idiom here, I guess.

> and you have too many objects, callbacks, or both.  Those
> objects are likely to be singletons.  Getting out Flyweight is an
> indication that the real world has stomped on your clean, elegant, but
> woefully inefficient design -- a hack we wouldn't need if we had infinite
> memory, cpu speed, or some other resource.
>
> What am I misunderstanding?

I don't know, because I can barely make out what you're
saying.  Anyway, there are several general cases where I
like "flyweight proxies" as opposed to using the singleton
design pattern, and not one of them seems best framed to
me as "a hack I wouldn't need" except for performance.

Say I have a class that models some thing of which, at
this stage of my design, I'm considering there can be
only one "live instance" -- maybe "the display screen",
maybe "the database I'm connected to", or "the printer".
Call it "the application-level class".

(In each of these cases, it's quite possible that the
program will need to evolve to have several screens,
several databases, etc -- the evolutionary push towards
once-singleton items to become non-singletons need not
distort my design _today_, but it's better to keep it
at the back of one's mind because it keeps coming up).

Some part of my system is already up and "the singleton"
(if it were one) is already instantiated.  Now, another
part comes up, say a GUI, or a web-interface that does
administrative things.  I'm likely to have a nice mixin
class which makes my life easy for GUI/web/whatever
purposes if I inherit from it, so I want to dress up
the application-level class, for purposes of this one
subsystem, and the easiest approach is to inherit from
it an from my mixin:

class SpiffyObject(AppLevelObject,SpiffyMixin):
    def __init__(self, whatever):
        # blah, blah, and so on

There's only one problem with that -- it doesn't work
if AppLevelObject implements the Singleton Pattern!

As "the one and only object that can possibly exist
in that class" has already been instantiated by the
other subsystem, it can't be instantiated again.  So
rather than using handy inheritance for code sharing
I have to explicitly hold that darned One&OnlyObject
and delegate to it appropriately.  Not as much of a
chore in Python as it would be in other languages,
sure, but still some deadweight boilerplate -- and
what is the advantage I'm buying with this cost?  None
that I can see (I _do_ keep looking -- it's been
years, and I still haven't found anything).  Not being
able to inherit also puts me in trouble if any other
code tests with isinstance, etc, of course.

So I just have AppLevelObject be freely, innocuously
instantiable as many times as it needs to be (all
instances sharing state with each other), and live
happily ever after.  I.e., "flyweight proxy".


Similarly: I have an object which holds a (oops, THE)
"one&only" -- can I persist it or otherwise stream it
freely and depersist/unstream it again?  Not with
the Singleton DP I can't, without (once again) going
to the trouble to implement special code for saving
and restoring, just because one of my attributes is
the cranky one&only.  Again, boilerplate in each
subsystem that needs to access the one&only as its
client.  A flyweight proxy can handle its own save
and restore needs (incredibly modest ones, to be sure,
as it gets its state from elsewhere:-) and make life
simpler for all the rest of the code, that uses it.


The exact problems change in each language and object
system, of course -- the loss of handiness in losing
multiple inheritance and thus mixins applies to C++
or Python, which DO have MI in the first place, but
not to languages that lack them; on the other hand,
C++ has its share of problems whenever one tries to
use smart-pointers & similar constructs around an
object that's not canonical (i.e. has a default ctor,
copy ctor, copy assignment, accessible dtor) -- COM
has _its own_ problems with Singletons, which are well
known -- and so on.  In general, an OO language's or
object-system's ordinary machinery seems to be rather
geared to ordinary objects -- ones that (depending on
language's/system's viewpoints) CAN be ordinarily
inherited/aggregated/extended/instantiated/persisted/
depersisted/copied/assigned/whatever.  Singleton DP
generally finds some way or other to trip you up with
some of these mechanisms in each language or system.


And when and if the time comes to migrate to "oops,
it's not just ONE printer any more, could be two or
three", again Singleton trips you up as its key
design assumption breaks down ruinously; flyweights
are more resilient -- they start sharing state in
groups or clusters, rather than all of them having
the _same_ state, but client code is remarkably
unaffected besides passing the appropriate arguments
to the relevant factory functions or __init__ calls.


Not sure what this has to do with "hacks for speed"
or resource limitations...


Alex






More information about the Python-list mailing list