Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-03-28 13:32:06


> DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com;
> h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:references;
> b=pF+Zvpraxj4DWHKMjzQDRNtCoQ+iETlCcRxdPY/967Dba6UptVfsPJa3+DVBRHCDo4Yts3/JhkPhE5bOK1ckoBgblZ1gU2pNeajuhu+GYkpZA56afZxcAAxCOIvwyaAMV2hSgs2L6NiM0DaGjSk/iqVQknAxL4WF4H+RAWiKl1Q=
From: Dan Rosen <dan.rosen_at_[hidden]>
>
> > What you've called
> > noninstantiable should be called singleton_base so that clients
> > derive from singleton_base.
>
> But singleton_base has no function other than to prevent a type from
> being instantiated. It has no semantics relating to singleton, so it
> seemed reasonable to decouple them. If you want to derive a class

Agreed, but...

> template called singleton_base<> from noninstantiable<>, for the
> (sole) purpose of making client code arguably a bit easier to follow,

Exactly. Rather than a Singleton library client needing to know
that they are making a Singleton class noninstantiable, they only
know they're declaring it to be used by the library. An advanced
usage section can document that deriving from the base class is
not needed, and that omitting that derivation permits separate
instantiations of the class.

> that's fine, but the noninstantiable<> / instantiable<> class template
> pair stand on their own in the absence of singleton. Anyway, this is
> getting far off-topic.

I'm not certain this is off topic. Yes, I agree that
noninstantiable/instantiable could be valuable components in
their own right. Whether singleton_base is implemented in terms
of noninstantiable, or is merely a duplicate of the technique
isn't worrisome to me.

> > The next point is whether requiring private ctor/dtor is better
> > than using a noninstantiable scheme (not necessarily the one
> > shown above).
>
> The main point I feel is being missed is that private ctor/dtor *is* a
> perfectly good "noninstantiable scheme." The only difference is that
> it's provided by the language, and requires no code trickery on our
> part.

I didn't miss that. I was simply thinking of it from the
perspective of the Singleton library client:

with:

class make_me_a_singleton : public singleton_base
{
...
};

without:

class make_me_a_singleton
{
...
private:
   make_me_a_singleton() { };
   ~make_me_a_singleton() { };
};

To me, the first ("with") version is clearer. It doesn't force
defining private ctor/dtors that aren't otherwise needed and its
intent is more apparent.

The first version is achievable just as easily with
noninstantiable as with singleton_base. If singleton_base offers
nothing more than noninstantiable, then the choice of names is
debatable.

> > The OP's goal is to prevent instantiation of a
> > type as both a Singleton and otherwise. [snip]
> > The question is whether the goal is acceptable. [snip]
> > I contend that you can provide a mechanism whereby clients can
> > ensure their type can only be instantiated by the Singleton
> > framework, but don't require that.
>
> I think you've just struck the heart of the issue here.
>
> I think there are three approaches: purposely allow the flexibility
> you're describing, purposely disallow it, or declare it "not my
> problem." If you're purposely allowing classes intended for use as

Good summary.

> singletons to be instantiated elsewhere anyway, you're no longer
> referring to the Singleton Pattern proper anymore. That's why I

It isn't clear that the library is or must slavishly follow the
GoF Singleton Pattern. It can support more functionality without
loss of clarity, IMO.

> thought the "noninstantiable" exercise was an interesting one: it
> purposely disallows instantiation in any other context, thus making
> the client class a singleton in the strictest sense.

Fine.

> But back to my point: I think the philosophical difference between our
> two ideas is that you are purposely allowing client classes to be
> instantiable outside of the singleton context by explicitly stating
> that "derivation from singleton_base is optional," whereas I'm saying
> "it's not my problem: if you want a true singleton, you'll do the
> right thing and prevent your class from being instantiated however you
> please."

To make the class instantiable by the framework, the supplied
Creator policy class must have access to the ctor. You can make
the ctor private and then make the Creator a friend, but then
outside code can call creator<T>::create() to create an
instance. If creator<T>::create() is private, and singleton<T>
is a friend, then only singleton<T> can instantiate a T. That,
of course, is a lot of machinery just to ensure that T can only
ever be instantiated as a Singleton.

It would be nice if T could be its own Creator. Then, using
CRTP, T could be noninstantiable and its own Creator by deriving
from, say, singleton::simple_singleton:

class make_me_a_singleton
   : public <simple_singleton<make_me_a_singleton>
{
   ...
};

My point is that just making the ctors private doesn't close the
access hole.

> To summarize: I feel the singleton framework should either strictly
> prevent all clients from being instantiated improperly, or shouldn't
> care at all. The third path, which I view as "optional strictness," is
> oxymoronic, and a waste of time for the singleton framework to attempt
> to provide.

It isn't a waste if it simplifies syntax.

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk