Board index » delphi » Thoughts on the Singleton design pattern

Thoughts on the Singleton design pattern

(This got a bit long. You might want to print it out and save it for the
next time you go to the bathroom, or maybe if you are having trouble
sleeping.)

Someone recently suggested the Singleton pattern as a way of
encapsulating a bunch of constants. For those not familiar with the
idea, a "Singleton" class is a class that allows only one instance of
itself. Repeated attempts to create another instance are denied in one
way or another.

So I thought I'd write one in Delphi. This would normally be a trivial
problem, but I had a few extra rules:

1. Syntactically, I wanted the creation to be identical to that of a
normal object. You should be able to say

ASingleton := TSingleton.Create;

to create it.

2. Repeated attempts to instantiate a Singleton object would silently
deny the instantiation and simply return the first and only Singleton.

3. Anyone who inherits from the Singleton class will have a Singleton
class themselves, without having to do any work, save for calling the
inherited constructor.

As it turns out, any two of these three can be done quite easily, but
getting all three to work together is tough. Here's what I've
discovered:

1. The creation syntax of the Singleton class can be identical to a
normal constructor, because of the way Delphi does its constructors. To
wit, it is impossible for the client to tell if it is calling a
constructor proper or just a class method. Compare this to C++, where
you have that crazy new operator (oh, I suppose you could overload it).
C++ implementations generally cede this point and resort to hiding the
constructor and using a static method like "Instance" (Gamma, et al).

Note that if you want to hide the constructor "Create", a public class
method of the same name is pretty much the only way to do it. Just
declaring "constructor Create" in the private section doesn't work,
because the compiler will default to finding the first public Create
constructor or class method in the inheritance chain. Yuck.

2. By using a class method instead of a constructor, we can effectively
deny the creation of any new Singletons and instead return a previous
instance. I know Delphi allows for exceptions in constructors, and will
supposedly clean up after itself, but I had difficulty with this.
Specifically, after the destructor executed, I got a message box with
the red X, but no text. Tracing it through the de{*word*81} didn't help. It
just happens. So, my scheme is as follows:

constructor TSingleton.ActualCreate; // This is private and virtual.
begin
  inherited Create;
  // Class-specific creation stuff.
end;

class function TSingleton.Create: TSingleton; // Public and virtual.
begin
  // Pseudo-code:
  if AlreadyCreated(Self) then
    Result := PrevInstance(Self)
  else
    Result := Self.ActualCreate;
end;

What "Self" is doing in the class function will become clear below.

3. Here's the tricky one: Making sure that people who inherit from
TSingleton don't have to do any work at all to make their class a
Singleton. In the implementation section of the unit, there is an
instance of a TSingletonRegistry class. TSingletonRegistry has a
TStringList, which holds the one allowed instance for each Singleton
class. It uses the metaclass information as a key. So, in the Create
function above, Self is actually the metaclass that describes the class
trying to be instantiated (since the method is virtual, we guarantee
that we'll always have the right metaclass, not just a "class of
TSingleton"). It passes that to the SingletonRegistry, which gets its
String description (using ClassName) and looks up its associated object,
if one exists.

This is slick, and it works well. So if you're still following, here's
where we have problems: A class that inherits from TSingleton has to do
more work than I like. Certainly a class should override the
ActualCreate constructor, inserting its own creation stuff and calling
inherited. However, a class *shouldn't* have to override the class
function Create. All of the checks are already correctly done in
TSingleton, by virtue of being a virtual function. But, Create can only
return a TSingleton instance, which isn't good enough.

Imagine I have a TMySingleton class. Its Create function should return
an instance of TMySingleton. But if it's going to override the original
Create function in TSingleton, it has to have the same Result type,
namely TSingleton. A variable of type TMySingleton, then, can't call
TMySingleton.Create, because that only returns a TSingleton, and thus
the statement will generate a compile-time error.

I have discovered two solutions, neither of which are satisfactory:

1. Don't override. Instead, just make a new virtual class function
called Create, which returns a TMySingleton instance. The body of the
function would then be

Result := TMySingleton(inherited Create);

or, perhaps more robustly,

Result := inherited Create as Self;

However, this requires the class writer to write more code than I like.
It violates the reusability principle, I think.

2. Make the original TSingleton.Create function return a Pointer. Then
everyone can override without thinking, or not even override at all.
However, this destroys all the type-checking that makes Delphi and OO so
nice.

The ultimate solution would be to have a function that always returns
its class type:

class function TSingleton.Create: WhateverTypeIAm; virtual;

This is generally called "covariance", and isn't allowed in too many
languages (C++, and some more arcane languages in academia).

The only way I could see to implement this in Delphi is through its
virtual constructor mechanism, but I haven't been able to raise
exceptions properly in constructors.

Thoughts, anyone?

Dave

 

Re:Thoughts on the Singleton design pattern


On Wed, 23 Sep 1998 10:04:01 -0600, Dave Shapiro <da...@cfxc.com>
wrote:

Quote
>Someone recently suggested the Singleton pattern as a way of
>encapsulating a bunch of constants.

Why?  They should be resolved during the build and come with no
run-time overhead.  Why use a class to package a bunch of constants?
And while, semantically you can call it encapsulation, I'd argue that
it is not in keeping with the true meaning.  After all, you hardly
need a class to package or organize a number of constants.  A record
structure would work as well.  But you begin to need the power of a
class for encapsulation because you also need behaviors to control
creation.  But if OP supported static class members, then you could
have a class without any methods add your constants as static class
members, and while a second object could in fact be created, it would
be of no consequence since all objects would share the same data.   In
fact OP's lack of support for static class members is specifically
offset by the fact that such behavior is handled at the unit level.
So now we're back at wondering why package them with a class at all?

That being said, I now need to go and take a long look at the rest of
your post because I am interested in the additional work of insuring
that only 1 instance of the class is created.   :)

Regards,

-- Jim Burns
     Technology Dynamics
       Pearland, Texas
         281.485.7186 / 281.485.0410
           jimbu...@technologydynamics.com

Re:Thoughts on the Singleton design pattern


Quote
Jim Burns wrote:

> On Wed, 23 Sep 1998 10:04:01 -0600, Dave Shapiro <da...@cfxc.com>
> wrote:

> >Someone recently suggested the Singleton pattern as a way of
> >encapsulating a bunch of constants.

> Why?  They should be resolved during the build and come with no
> run-time overhead.  Why use a class to package a bunch of constants?

I actually never considered using a Singleton for this purpose, but
after giving it some more thought, I can see some advantages. Most
importantly, a Singleton can allow for lazy initialization; that is,
none of its contents are available or even created until you ask for
them. This can reduce executable size and decrease load time,
particularly if you have constants whose values depend on something at
run time.

Example: What if you needed a constant which consisted of the contents
of some huge file on the client's machine? If you knew the contents at
design time, you could compile them in and bloat your executable.
Otherwise, you'd have to fetch them at run time. If you didn't use a
class-based approach, you'd probably put the code to get the data in the
unit's initialization section. Now, this code gets run as soon as the
unit is initialized. But what if, under certain circumstances, you never
needed these contents? You've just wasted some time getting all this
information. With the class-based approach, you don't waste any time,
because the data are only fetched when you want them. And with the
Singleton scheme, you don't run the risk of retrieving the data more
than once; additional queries result in a simple lookup. Furthermore,
what if you decide later on that the file from which the data come might
change during execution? With the non-class-based approach, you now have
to move your initialization code into a general routine that can be
called whenever. With the class-based approach, you just don't inherit
from the Singleton class anymore. (In re-reading this, I realize that
the situation I'm talking about isn't really "constant". My apologies
for taking the initial point and running with it.)

Even if you're just using the class to hold some static information like
a bunch of Longints, the class-based approach can be superior, because
classes contain some pertinent features that units don't, namely the
ability to possess read-only data, or data that only the class itself
can change. Using the "const" directive in the interface portion can be
restrictive. Furthermore, "typed constants", like

const
  MyArray: array [1..10] of Longint;

are easily modified at run-time by anyone using the unit (unless you
compile with that switch that prevents this, but what a pain. And again,
what if the owning unit wanted to change the data?). A class-based
approach could resolve all of this, using indexed read-only properties
and the whatnot.

To be sure, these examples are a little contrived, but in a world where
bugs and other improperly-written forms of software are not only
prevalent but expected, I'm all for promoting correctness at all levels.

Quote
> After all, you hardly need a class to package or organize a number
> of constants.  A record structure would work as well.  But you begin
> to need the power of a class for encapsulation because you also need
> behaviors to control creation.

A publicly visible record structure would need to be in the interface
section, and as such would be readily modifiable by any miscreant, or
even any benevolent-but-still-human programmer. Classes provide
behaviors to control creation that units don't, but they also provide
behaviors to control access.

Quote
> But if OP supported static class members, then you could
> have a class without any methods add your constants as static class
> members, and while a second object could in fact be created, it would
> be of no consequence since all objects would share the same data.   In
> fact OP's lack of support for static class members is specifically
> offset by the fact that such behavior is handled at the unit level.

I miss static class members. I think Java got it right. In fact, a nice
way of implementing constants in Java is to put them in an interface,
where no methods are even allowed. Then everything just gets declared

public static final int myInt = 561;

or whatever.

Anyway, the point, for me, of using a Singleton class is to represent
things of which one only really exists. Take the Windows clipboard.
There's only one of 'em. The VCL does attempt to make this clear. From
the help file:

"The Clipbrd unit automatically instantiates a TClipboard. Use a
clipboard object in the manner rather than by instantiating it by
calling the Create constructor. The Clipboard function safeguards
accidently deleting the clipboard."

Indeed, looking at the source, the Clipboard function does do this, but
you can *still* call TClipboard.Create! It could be safer.

Quote
> That being said, I now need to go and take a long look at the rest of
> your post because I am interested in the additional work of insuring
> that only 1 instance of the class is created.   :)

Yes, please do. I welcome any ideas from anyone. I hope I haven't found
a small limitation in OP's syntax, but I suppose anything's possible.
:^)

Dave

Re:Thoughts on the Singleton design pattern


Dave, et al.

This is an excellent post, and requires some more thought... I
especially like the use of RTTI... however, I'm too drunk to answer at
the moment... but a big long reply will follow in a day or two :-)

MH.

--
Martin Harvey

mailto:mar...@aziraphale.demon.co.uk
http://www.harvey27.demon.co.uk/mch24/

Re:Thoughts on the Singleton design pattern


Quote
Dave Shapiro wrote:

> (This got a bit long. You might want to print it out and save it for the
> next time you go to the bathroom, or maybe if you are having trouble
> sleeping.)

> Someone recently suggested the Singleton pattern as a way of
> encapsulating a bunch of constants. For those not familiar with the
> idea, a "Singleton" class is a class that allows only one instance of
> itself. Repeated attempts to create another instance are denied in one
> way or another.

> So I thought I'd write one in Delphi. This would normally be a trivial
> problem, but I had a few extra rules:

I am not sure, if it will help, but you can check:

http://www.obsof.com/pattern.html

Michael

Other Threads