Singleton vs Proxies DP (was Re: Solution: Direct access to Printer I/O lines)

Alex Martelli aleaxit at yahoo.com
Mon Dec 18 04:46:29 EST 2000


"Dinu C. Gherman" <gherman at darwin.in-berlin.de> wrote in message
news:3A3D1D49.1A453B51 at darwin.in-berlin.de...
> Alex Martelli wrote:
> >
> > I agree that unique id is part of the Singleton Pattern:
> > that is what makes it problematic.  One does not really
> > _care_ about that identity, only about the state and
> > behavior it represents.
>
> For me it sounds like being part of the essence of that
> pattern... but you're free to disagree.

Identity is 'part of the essence' only if a typical use case
includes client-code doing identity checks -- in Python:
    same = a is b
or
    same = id(a) == id(b)
or, in C++:
    bool same = dynamic_cast<void*>(a) == dynamic_cast<void*>(b)
or, in COM:
    IUnknown *pUa, *pUb;
    a->QueryInterface(IID_IUnknown, (void**)&pUa);
    b->QueryInterface(IID_IUnknown, (void**)&pUb);
    bool same = pUa == pUb;
    pUa->Release();
    pUb->Release();
and so on, and so forth.

This is so far from typical that the language-idiom for
object-identity-checking is considered one of the 'obscure'
parts of C++.  It's not quite so obscure in Python, given
the 'is' keyword and easy exposure of 'id', and the COM
idiom is well-known, since it's what _defines_ the notion
of object-identity in that object-model... which is very
relevant to (e.g.) remoting-infrastructure supplied by it
(proxy/stub and marshaling issues).

But _usage in 'normal', "application"-level, client-code_
is still pretty unusual, whatever the implementation language;
indeed, if I had a situation in COM where identity-checks
_did_ come up as an important use-case, I would much rather
choose to expose an Identity *property* from the relevant
object, to decouple "application-level" checks from
infrastructure-level identity notions and implications (I'd
rather keep my ability to, e.g., tweak/optimize delicate
marshaling situations which might arise in different remoting
and deployment scenarios, than be constrainted in such
implementation level fine-tuning optimizations by
application-level semantic needs!).

Using a GUID as the type/representation for 'identity' would
also be more flexible in several ways, rather than having
to have application-level code keep the library-side object
alive just to be able to later check 'if it's still the same':
GUID's can be easily persisted and depersisted, do not imply
continuing connection between client and server (and thus,
maybe, 'keep-alive' protocol overhead in a remote scenario),
and don't go against the grain of MTS/COM+ or other cases of
transactioning (where object-identity as naively seen by many
OO analists/designers/coders is often problematic, or can at
the very least carry substantial scalability costs).  Similar
advantages for system-level-id / application-level-identity
decoupling appear in Python and C++, though the semi-transparent
remoting possibilites of COM & friends (and the system-level
services 'keyed' on system-level-identity) make it stand out.

To reiterate, that's even in the _rare_ case where application
semantics DO require checking equality of identities for
system-supplied 'unique' ('singleton') objects; such requirements
are *not* typical.


> > No!  I'm not saying two clients can't hold their
> > 'handles' (lw proxies) at the same time.  It IS
> > pretty typical.  But it's not at all typical for client
> > code to be interested in ensuring _identity_ --
> > state and behavior are typical.
>
> In the context of Singletons I would even reduce that to
> state only, like with counters of some system-wide entities
> of I-don't-know-what. A client is "typically" not able to
> compare *bahaviour*, but state, yes. In all cases where

A client is not able to *compare* behavior, but it IS,
typically, quite interested in getting server-side objects
with "just THAT behavior", just as it is interested in
getting them with "just THAT state" -- even the portions
of the state which it's not meant to access directly, in
as much as they do affect behavior.  "Is not meant to"
may mean relatively little in a pure-Python scenario, as
client-code *may* choose to dig into object internals
even though it _shouldn't_, but object models providing
stronger encapsulation may even make portions of state
_totally unaccessible_ by the client (e.g., that IS quite
common for COM, Corba, and other object models with some
orientation to remoting).

So client code *ASKS* in some way for the state and
behavior it needs (in some abstract terms) and it's the
server-side (library, etc) job to supply an object that
works right for those requests.  "Works right" and "has
a specified identity which the client can compare to
other object identities" do not need to be coupled, and
such coupling as enforced in the Singleton Pattern as
the GoF wrote it up is typically a design weakness.

> this comparison is difficult or time-consuming, comparing
> or, probably more often in fact, *accessing* the current
> state via a "globally identical" object is what a Singleton
> is about - if I understood anything at all about this
> pattern.

I do agree that the GoF-Singleton-Pattern IS "about"
global identity -- that's exactly why I'm dissing it,
in favour of patterns that decouple the actual identity
of the objects that the library/server/whatever supplies,
from the state-and-behavior issues that are client-side's
typical needs and interests.

My claim, in your terms, is that *client-side needs* are
NOT "about" verifiable ('system-level') object-identity,
and quite rarely 'about' object-identity at all; thus,
it is not optimal to answer such needs with a design
pattern that _hinges_ on object-identity.


Alex






More information about the Python-list mailing list