How to get a Singleton in Eiffel?
Karine Arnout, Swiss Federal Institute of Technology,
Zurich, Switzerland
Éric Bezault, Axa Rosenberg, U.S.A.
|
 |
TOOLS USA
2003
PROCEEDINGS

PDF Version |
Abstract
Can the Singleton pattern [Gamma95] be turned into a reusable component?
To help answer this question, we have reviewed existing implementations
and tried to improve them. This article explains the difficulties of
having a single-instance class in Eiffel and proposes language extensions,
namely once creation procedures, which would be satisfactory in most
cases, or frozen classes.
1 INTRODUCTION
Achieving reusability in software is one of the core goals of object
technology and key aspect of software quality. “Quality through
components” [Arnout02] should be the motto for all software
programmers. However, much code is still written anew whenever a new
project starts
without benefiting from previous similar developments.
This is particularly
true for design patterns [Gamma95] [Vliss98]. Most existing implementations
are just possible ways to get the pattern
in a particular context and a given example. But an example — or
a template — is not a reusable library. One should pursue a higher
degree of reuse and examine whether the pattern mechanism could be
provided in a component that clients could reuse off-the-shelf and
just focus on the implementation part that is specific to their applications.
The Eiffel event library [Arslan03] [Meyer03], which provides the
subscription/notification mechanisms of the Observer design attern,
shows that building reusable components from design patterns is not
a pure utopia.
The rest of this presentation focuses on one “creational
design pattern” [Gamma95]: the Singleton. First we examine
existing attempts to implement the Singleton pattern, and
discuss their limitations; then we propose an extension to the Eiffel
language that
would facilitate
writing singletons in Eiffel:
Section 2 focuses on the Singleton pattern:
it describes the difficulty (even impossibility) to obtain single-instance
classes in
current status
of the Eiffel programming language with concrete examples.
Section 3
proposes to loosen the existing creation clause rule of Eiffel to allow
once creation procedures, supplies an appropriate semantics,
and discusses the limitations of such a solution.
Section 4 explores
a language extension that already exists in Eiffel for .NET, namely
frozen classes.
Section 5 concludes with an assessment of the analysis
performed and gives further research directions.
The analysis reported
here is part of a broader research plan of trying to turn design
patterns described in the Design Patterns book
[Gamma95] (at least some of them) into reusable components.
2 SINGLETON
The Singleton pattern
The intent of the Singleton pattern is to “ensure
a class only has one instance, and provide a global point of access
to it” ([Gamma95],
p 127).
The following diagram shows the classes involved in the Singleton pattern
and the relationships between them ([Jézéq99], p 79):

Fig. 1: Class diagram of the Singleton Pattern
Note that
class SHARED_SINGLETON was called SINGLETON_ACCESSOR in
[Jézéq99].
We changed its name to better comply with well accepted Eiffel naming
conventions.
How to get a “Singleton” in Eiffel
The Design Patterns book [Gamma95] explains with C++ examples how difficult it may be to
ensure that a class has no more than one instance. C++
uses static functions for that purpose. Since Eiffel does not have
static features, we need to explore another way: once routines.
Although the Eiffel programming language natively includes a keyword — once — which
guarantees that a function is executed only once (subsequent calls
return the same value as the one computed at first call), the implementation
of the Singleton pattern is not trivial.
Note that once routines are
executed once in the whole system not once per class.
The Design Patterns
and Contracts book [Jézéq99] tries
but fails [JézéqErr] to provide a solution. Let’s
examine the proposed scheme to identify what was wrong with it and
attempt to correct it.
The Design Patterns and Contracts solution
Here is the approach suggested
in [Jézéq99]: Make a class
inherit from SINGLETON (Fig.
2) to specify that it can only have one
instance thanks to its invariant and provide a global access point
to it through a class SHARED_SINGLETON (Fig.
3).

Fig. 2: Class SINGLETON
Fig. 3: Class SHARED_SINGLETON (Access point to SINGLETON)
In fact,
as explained in the errata of the book [JézéqErr], such
an implementation does not work: it allows only one singleton per system. Indeed,
if one inherits from class SINGLETON several
times, the feature the_singleton (Fig.
2), because it is a once function inherited by all descendant classes,
would keep the value of the first created instance, and then all these descendants
would share the same value. This is not what we want because it would violate
the invariant of SINGLETON in all its descendant
classes except the one for which the singleton was created first.
One would
need “once per class semantics to create singletons as
suggested by the book. Since the concept does not exist in Eiffel, [one]
then [has] to
copy all the code that is in SINGLETON to [one’s] actual
singletons” [JézéqErr].
The last sentence by Jean-Marc
Jézéquel suggests writing a “singleton
skeleton” in Eiffel. We will now examine this approach.
Singleton “skeleton”
Fig. 4 shows a possible “skeleton” for
the singleton pattern:

Fig. 4: Singleton skeleton
With:
Fig. 5: Class SINGLETON used by the Singleton skeleton (wrong
solution)
What’s wrong with this implementation?
In spite of the name is_real_singleton,
this code does not provide a “real” singleton. Declaring singleton as
a once function does ensure that any call to this function returns
the same object,
but nothing prevents the program from creating another instance of
class SINGLETON somewhere else in
the code, which breaks the whole idea of a singleton.
Having an invariant
in class SINGLETON to
detect attempts to create a singleton twice is not a proper solution
either. The problem is that,
in debugging mode, even though the invariant will catch errors at run-time
when the singleton pattern is violated, clients of class SINGLETON have
no means to ensure that this invariant will never be violated (they
cannot test for it as they can do for a precondition before calling
a routine), which reveals a bug in the implementation of the class.
The Design by Contract™ method gives the following definition
of class correctness ([Meyer92], p 128; [Meyer97], p 370):
Fig. 6: Definition of class correctness
A violation of {Defaultc
and prep (xp)} or {prer (xr) and INV} is
the manifestation of a bug in the client.
A violation of {postp
(xp) and INV} or {postr
(xr) and INV} is the
manifestation of a bug in the supplier.
How is class correctness related
with this singleton implementation?
The definition of the singleton
pattern given in [Gamma95] (p 127) states that the corresponding class
should have at most one instance,
which means that we want to prevent creating more than one such object.
In other words, as a client of class SINGLETON, I want to
know whether the instruction:
create s.make
with:
s: SINGLETON
is valid before calling
it, hence I want to write code like:

The problem with class SINGLETON is
that it provides no way to ensure the condition is_valid_to_create_a_new_instance before
calling Bodyp.
Since we are dealing
with creation routines, the relevant rule for assessing class correctness is
C1. We will get a violation of INV (on the right
hand side of the formula) if we create a second instance of the class. This
indicates a bug in the class
SINGLETON itself, not in the client of the
class.
Note that restricting access of the creation procedure of SINGLETON to class SHARED_SINGLETON would still not ensure correctness since one can
inherit from
SHARED_SINGLETON — and this is the expected way to use SHARED_SINGLETON to get access to feature singleton — and then call a creation procedure
on SINGLETON at will. A possible solution — although not perfect because
it violates the Open-Closed principle, [Meyer97] p 57-61 — is to
use frozen classes (classes from which one cannot inherit) as we describe
later
(see section 4), but the current version of Eiffel does not authorize
them (it only allows frozen features).
Besides, relying on the evaluation of invariants
to guarantee the correctness of a class is not good design: a program should
behave the same way regardless
of the assertion monitoring level.
Tentative correction: Singleton with
creation control
Let’s try to correct the previous implementation
and define a Boolean feature may_create_singleton in SINGLETON accessor
(Fig. 7 and 8).

Fig. 7: Singleton with creation control (wrong solution)
Fig. 8: Accessor to singleton with creation control (wrong solution)
However, the feature may_create_singleton does
not solve the correctness problem detailed earlier: it does not prevent
from calling two creation
instructions as in the following example (Fig. 9)
and breaking our “singleton”.

Fig. 9: Class breaking the singleton with creation control
Indeed, MY_TEST does not call the
once function singleton of class
MY_SHARED_SINGLETON, which means
that may_create_singleton is never
set to False and both s1 and s2 get
instantiated.
The important point here is that we have broken the “singleton
skeleton” by just looking at the interface forms of classes MY_SINGLETON
and MY_SHARED_SINGLETON and writing code that does not violate the
Design by Contract principles (although it would violate an invariant
when executed!).
The interface form of a class retains only specification-related
information of the publicly available features: the signature of features
(of both
immediate and inherited features), the comments, and contracts (involving
exported features only), namely what a client of the class needs to
know about.
The Gobo Eiffel singleton example
Fig. 10 and 11 show a better approach
to the “singleton pattern
problem” in Eiffel. (It is a Gobo Eiffel Example [Gobo].)

Fig. 10: The Gobo Eiffel singleton example

Fig. 11: Accessor to the Gobo Eiffel singleton example
This implementation is still not perfect; one can still violate the
invariant of class MY_SINGLETON by:
cloning
a singleton — using feature clone or deep_clone from
ANY;
using persistence — retrieving
a “singleton” object
that had been stored before (using the STORABLE mechanism
of Eiffel or a database library);
inheriting from MY_SHARED_SINGLETON and “cheating” by
putting back Void to
the cell after the singleton has already been created. Note though
that
here one needs to access and modify non-exported features — in
this case singleton_cell — to “break” the
singleton implementation given above (Fig. 10 and 11), whereas one
could “break” the
code defined previously (Fig. 7, and 8) easily by looking only at the
interface of the classes.
Besides, the use of the invariant
Current = singleton
is not fully
satisfactory because it means that descendants of this class may not
have their own direct instances without breaking this
invariant.
Eiffel distinguishes between direct instances and instances
of a type T, the latter including
the direct instances of type T and
those of any type conforming to T (i.e.
its descendants) [Meyer92]. We think
it should be the duty of the users of the Singleton library to
decide when implementing a singleton whether there should be only
one instance
or only one direct instance of that type; it shouldn’t be
up to the authors of the library to decide.
Finally, this code is not a
library component: it is just an example implementing (or trying to
implement) the singleton pattern.
Other tentative implementations
In a discussion in the comp.lang.eiffel
newsgroup [Cohen01], Paul Cohen gives an interesting but somewhat overweight
solution. The idea is
that the singletons in system can register their instance by name in
a registry. The Design Patterns book [Gamma95] calls it the “registry
of singletons” approach (see 2. Subclassing the Singleton
class,
p 130). Fig. 12 gives the corresponding Eiffel implementation:

Fig. 12: A “registry of singletons”
Feature generating_type is
defined in class ANY; it returns a string
corresponding to the name of current object’s generating type
(namely the type of which it is a direct instance). It is a feature
of the Eiffel Library Kernel Standard (ELKS, see [Gobosoft] and appendix
A of ETL3 [Meyer0?a]). However, class HASH_TABLE is
not a standard Eiffel class (for example, SmartEiffel [Inria] does
not define it).
Let’s write a descendant of class SINGLETON to
understand how this “registry of singletons” works. A particular
singleton implementation should look like the one shown in Fig. 13:
Fig. 13:A particular singleton in the “registry”
Each
time a singleton gets created, it adds itself to the registry of singleton.
The problem with this approach is that a client of MY_SINGLETON cannot
test for the precondition of make before
calling the routine: first, it does not have access to singletons_in_system;
second, it does not know about the value of generating_type because
the corresponding object has not been created yet.
Doug Pardee gives another
possible implementation of the Singleton pattern in the Eiffel Forum [Pardee01],
but it seems too complex to be reused effectively.
Impossible?
The unfruitful attempts reviewed so far illustrate how
difficult it is to implement the singleton pattern in Eiffel, especially
as a
reusable library.
In fact,
it is not possible at all without violating the Design by Contract principles,
namely a non-checkable invariant, even when controlling the creation of the
singleton object because it can get involved in some cloning (clone/deep_clone)
or in some persistence mechanisms (store/retrieve from STORABLE,
or a database library).
Assuming we do not take clone and STORABLE into account,
one solution could
be to allow once creation procedures in Eiffel with a special semantics
ensuring class correctness. That’s what we will review now.
3
ONCE CREATION PROCEDURES
We propose an extension to the Eiffel programming
language that would allow declaring a creation procedure as a once-procedure — which
is currently forbidden by the sixth clause of the “Creation Instruction
rule”,
[Meyer92] p 286. (This idea first appeared in the newsgroup comp.lang.eiffel
in 2001 [Silva01].)
Rationale
Let’s consider a creation instruction with target x,
a creation reference type TC and a creation procedure make:
x: TC
create x.make
The semantics of the Creation instruction ([Meyer92],
p 289) for a reference creation type TC is
as follows:
- Allocate memory.
- Initialize the fields with their default
values.
- Call the creation procedure make (to ensure the invariant).
- Attach the resulting object to the creation target entity x.
This semantics
forbids the use of once-procedures as creation procedures. Indeed,
with a once procedure, the first object created would satisfy the
class invariant
(assuming the creation procedure is correct), but subsequent creation instructions
would not execute the call, and hence would limit themselves to the default
initializations, which might not ensure the invariant.
But we could think
of another semantics for the “Creation_instruction” when
the creation procedure is a once-procedure (namely a procedure declared
as once):
If the once creation procedure has not been called yet to
create an object of the given type TC then create an object as indicated
above
(steps 1
to 4).
Otherwise attach to the creation target entity x the object which
has been created by the first call to the once creation procedure
for this
type.
This new semantics would make it possible to write a Singleton
pattern in Eiffel (Fig. 14 and 15) and would also simplify the implementation
of shared
objects.
Fig. 14: Class SINGLETON with once creation procedures
Fig. 15: Feature using a singleton (declared with a once creation
procedure)
Another possible application would be in the field of graphical
user interfaces to display error messages in the same window:
(create {ERROR_WINDOW}).display (error_message)
default_create being declared
as a once creation procedure.
For these examples to be valid, one should
remove the sixth clause from the “Creation
Instruction rule” ([Meyer92], p 286).
Open issues
Expanded creation type: It is not clear yet what
should be the semantics when the creation type is expanded. Here is
a possible
solution:
If the once creation procedure has not been called yet in
a creation instruction/expression of creation type TC then
apply steps 3 and 4 described above to the object
attached to x.
Otherwise do nothing.
Creation instruction and “onceness” status:
Loosening the creation validity constraints ([Meyer92], p 286) to allow
once creation procedures and
applying the semantics described above would mean that a once-procedure has
several “onceness” statuses (i.e. is it the first or a subsequent
call?):
when it is called as a regular procedure
when it is called as a creation
procedure (for each type for which it is declared as creation procedure).
Let’s consider an example to better understand the issue:

Fig. 16: Class A declaring a once creation procedure
Fig. 17: Descendant class B inheriting once creation procedure from A
Fig. 18: Feature using once creation procedure from classes A and
B
If it is clear that a1 and a2 should
be attached to the same object, and likewise for b1 and b2,
however it is not the case of a1 and b1,
which have two different
creation types and thus cannot be attached to the same object. Therefore the “onceness” status
of make should be per creation type. But make can
also be called as a regular procedure:
a1.make
b2.make
Should we take into account whether make has
already been called as a creation procedure or not in that case? In
our opinion, the “onceness” of
a procedure should be different when used as a creation procedure and when
used as a regular procedure. Indeed, even if the once-procedure has already
been called as a regular procedure, we still want the initialization of the
object to be made properly when this procedure is called for the first time
as part of a creation instruction:
a1.make
create a2.make
Finally, we should probably combine all the above with
the semantics of “once
per thread”, “once per process”, etc. mentioned in section
8.6 of ETL3 [Meyer0?a].
Limitations
Coming back to our discussion about the Singleton pattern,
once creation procedures in Eiffel still would not completely solve
the issues
described in section
2; in particular:
We would still have the problem of not being able to forbid
the duplication of the singleton object with clone/deep_clone
or STORABLE/databases.
We would not have the global access point to the singleton as demanded
by the definition of a singleton in the Design Patterns book ([Gamma95],
p 127) although
we can provide a SHARED_SINGLETON access
with a once function per SINGLETON class.
Another
approach would be to extend the notion of frozen features ([Meyer92], p 63)
to frozen classes as it already exists in Eiffel for .NET. We will now
review the pros and cons of this solution.
4 FROZEN CLASSES
Eiffel: The Language ([Meyer92], p 63) defines
the notion of frozen features, namely features that
cannot be redefined in descendants
(their declaration
is final). By broadening the scope of final declarations from features to
classes — as
already done in the current implementation of Eiffel for .NET — it
would become possible to implement a “real” singleton in Eiffel
with a proper access point (as defined in [Gamma95], p 127) as a reusable
component.
Rationale
Eiffel features whose declaration starts with the frozenkeyword
are final: they are not subject to redefinition in descendants. They
are called “frozen
features”.
The idea is to extend this notion to classes. The semantics
of “frozen
classes” is that one may not inherit from these classes, which as
a consequence cannot be deferred (because they cannot have any descendants
and could never
be effected).
The only syntactical change to the Eiffel language would be
the introduction
of the keyword frozen on classes.
The Header_mark defined in section
4.8 of [Meyer92] (p 50) should be extended to:

with the consequence that
a class cannot be both frozen and deferred.
The keywords reference and
separate do not appear in the
first two versions of Eiffel; they are novelties of the third edition
(see ETL3
[Meyer0?a],
section 4.9, p 65).
Singleton library using frozen classes
Having frozen classes would
enable writing a “singleton library” relying
on two classes:
A frozen class SHARED_SINGLETON (Fig. 19) exposing
a feature singleton, which is a once function returning an instance
of type SINGLETON.
A class SINGLETON (Fig. 20) whose creation procedure
make is exported to class SHARED_SINGLETON and its descendants only.

Fig. 19: Frozen class SHARED_SINGLETON (global access point to SINGLETON)
Fig. 20: Class SINGLETON
Typical use of the “Singleton library” would be to create a SHARED_SINGLETON
to get one’s own unique instance, as in class MY_SHARED_SINGLETON written
below (Fig. 21).

Fig. 21: Typical use of the “Singleton library”
Pros and
cons of introducing frozen classes
Weak point:
- The disadvantage of frozen classes is that it goes against
the core principles of object-oriented development. Indeed, the Open-Closed
principle ([Meyer97],
p 57-61) states that a module should always be both closed (meaning usable
by clients) and open (meaning it can be extended). Having frozen classes, which
by definition cannot be redefined, violates this principle.
Strong points:
- The main advantage of the last solution using frozen
classes is that it provides a very straightforward way (introduction
of just one
keyword, frozen, with
the appropriate semantics) to get a real singleton in Eiffel, including a
global access point to it — which one could not have with
the solution using once creation procedures.
- Besides, there is no such problem as different once
statuses depending on whether the same feature is called as a creation
procedure or as a regular procedure.
- On a lower level, having frozen classes would enable
the compiler to perform code optimization, which it could not
do for non-final classes.
5 CONCLUSION
This analysis has shown that implementing the Singleton
pattern [Gamma95] as a reusable library in Eiffel is not feasible
with the current
definition of
the language; an implementation like the Gobo Eiffel example [Gobo-Eiffel]
is acceptable, but it is neither secure nor robust.
Among the two Eiffel language
extensions suggested in this paper, the introduction of frozen classes is
the most elegant and would lead to a straightforward way
of writing “real” singletons in Eiffel (including a global access
point). The main argument against authorizing frozen classes is that users
may start using them excessively, which would violate the Open-Closed
principle ([Meyer97],
p 57-61); we believe it will not be the case. Indeed, Eiffel developers already
have the possibility to declare features as “frozen” (meaning
these features may not be redefined), but they use it only sparsely, in well-identified
and justified cases. Besides, the utility of frozen classes is wider than
just the implementation of the Singleton pattern; for example, it is already
used
in the .NET extension of the Eiffel language.
We think that extending Eiffel
with frozen classes would provide an elegant way of writing real singletons
in Eiffel. Nevertheless, it would not enable — at
least we have not succeeded in — having reusable library components
corresponding to the Singleton pattern.
REFERENCES
[Arnout02] Karine Arnout. “Contracts and Tests”.
Ph.D. research plan, ETH Zurich, December 2002.
http://se.inf.ethz.ch/people/arnout/phd_research_plan.pdf.
[Arslan03] Volkan Arslan, Piotr Nienaltowski, and Karine Arnout. “Event
library: an object-oriented library for event-driven design”. JMLC
(Joint Modular Languages Conference), Klagenfurt, Austria, August 25-27,
2003.
http://se.inf.ethz.ch/people/arslan/data/scoop/conferences/Event_Library_JMLC_2003_Arslan.pdf.
[Cohen01]
Paul Cohen. “Re: Working singleton implementation”. In
newsgroup comp.lang.eiffel [online discussion group]. Cited 15 April
2001.
http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF-8&selm=3AD984B6.CCEC91AA%40enea.se&rnum=8.
[Eiffel]
Eiffel Forum: Singleton Pattern In Eiffel.
http://efsa.sourceforge.net/cgi-bin/view/Main/SingletonPatternInEiffel.
[Gamma95]Erich
Gamma, Richard Helm, Ralph Johnson, and John Vlissides: Design
Patterns.
Addison-Wesley, 1995.
[Gobo] Gobo Eiffel Example: gobo-eiffel/gobo/example/pattern/singleton.
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/gobo-eiffel/gobo/example/pattern/singleton/.
[Gobosoft] Gobosoft: The Eiffel Library Kernel Standard, 2001
Vintage.
http://www.gobosoft.com/eiffel/nice/elks01/index.html.
[Inria] INRIA,
Loria: Welcome to SmartEiffel! Home of the GNU Eiffel Compiler,
Tools, and Libraries. http://smarteiffel.loria.fr/.
[Jézéq99]
Jean-Marc Jézéquel, Michel Train, and
Christine Mingins: Design Patterns and Contracts. Addison-Wesley, 1999.
[JézéqErr]
Jean-Marc Jézéquel: Errata.
http://www.irisa.fr/prive/jezequel/DesignPatterns/#Errata.
[Meyer92] Bertrand Meyer: Eiffel: The Language. Prentice Hall,
1992.
[Meyer94] Bertrand Meyer: Reusable Software: The Base Object-Oriented
Component Libraries. Prentice Hall, 1994.
[Meyer97] Bertrand Meyer:
Object-Oriented Software Construction, second edition. Prentice Hall,
1997.
[Meyer0?a] Bertrand Meyer: Eiffel: The Language, Third edition
(in preparation). http://www.inf.ethz.ch/personal/meyer/#Progress.
[Meyer03] Bertrand Meyer. “The power of abstraction, reuse and
simplicity: an object-oriented library for event-driven design”.
In Festschrift in Honor of Ole-Johan Dahl, Eds. Olaf Owe et
al., Springer-Verlag, Lecture Notes in Computer Science 2635, 2003. Available from
http://www.inf.ethz.ch/~meyer/publications/events/events.pdf.
Accessed June 2003.
[Silva01]
Miguel Oliveira e Silva. “Once creation procedures”.
In newsgroup comp.lang.eiffel [online discussion group]. Cited 7 September
2001.
See this URL.
[Pardee01] Doug Pardee. “Re: Once creation procedures”.
In newsgroup comp.lang.eiffel [online discussion group]. Cited 8 September
2001.
See this URL.
[Vliss98] John Vlissides: Pattern Hatching: Design Patterns Applied.
Addison-Wesley, USA, 1998.
ACKNOWLEDGEMENTS
We gratefully acknowledge Bertrand Meyer (ETH Zurich & Eiffel
Software Inc.) for his valuable comments and feedback on the paper.
We are also
thankful to Emmanuel Stapf (Eiffel Software Inc.), Mark Howard (Axa
Rosenberg), and
Dominique Colnet (LORIA), members of the standardization committee
ECMA TC39-TG4 for fruitful discussions about once creation procedures
and frozen classes.
About the authors

|
 |
Karine Arnout is Ph.D. student in the
Chair of Software Engineering held by Prof. Dr. Bertrand Meyer
at ETH Zurich. Her Ph.D. topic deals with contracts and tests.
She is a member of the ECMA working group standardizing Eiffel
and worked at Eiffel Software on porting Eiffel to .NET. She can
be reached at Karine.Arnout@inf.ethz.ch. |
 |
|
Éric Bezault is a senior engineer
at Axa Rosenberg, research center, USA. He is the leader of the
Gobo Eiffel Project, which provides free and portable Eiffel tools
and libraries. He has several years experience on Eiffel projects
in the financial industry. He is member of the ECMA group standardizing
Eiffel. He can be reached at ericb@gobosoft.com. |
Cite this article as follows: Karine Arnout, Eric Bezault: “How
to get a Singleton in Eiffel?”, in Journal of Object Technology,
vol. 3, no. 4, April 2004, Special issue: TOOLS USA 2003, pp. 75-95.
http://www.jot.fm/issues/issue_2004_04/article5
|