Sign in Join
Wiki copytemporary

Singleton Pattern: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# Introduction
22
33Considered one of the simplest patterns, it probably is the most discussed pattern: the singleton. What is so difficult to this pattern? Well, no matter the language in which you implement it, you have to do some counter intuitive things to reap all the benefits of the pattern. Every programming language has it's own quirks with this pattern, FreePascal is no exception. As a result, any implementation may lead to discussion and the choices you make for the implementation will be against the principles of another programmer. The implementation of this pattern is never ideal, the approaches provided in this article included. Yet, I hope this article is useful for you.
44
55## What You Will Learn
66
77- The benefits of the Singleton pattern and why to avoid it
88- Global variables and class variables in FreePascal
99- How to hide the constructor and keep it private
1010
1111## Acknowledgement
1212
1313I didn't think up the examples and the arguments. I found the examples in forum discussions and their archives. This article is a overview of the discussion about singletons and a collection of the usable examples I found.
1414
1515- [Making a Singleton class](http://community.freepascal.org:10000/bboards/message?message_id=234708&forum_id=24097)
1616- [Implementing a true Singleton - Can we decrease the visibility of a method?](http://lists.freepascal.org/lists/fpc-pascal/2006-December/012826.html)
1717- [Warning: Constructor should be public](http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg13833.html)
1818- [Compiler Warning: Constructor should be public](http://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg18257.html)
1919- TDockManager
2020- Printers4Lazarus package
2121
2222# The Pattern
2323
2424## The diagram
2525
2626![The Singleton pattern](/wiki-images/5/56/250pxSingleton.png)\
2727The Singleton pattern is described in the above image. The Singleton class defines a private class variable that holds the Singleton instance. The class method *GetInstance* creates that instance once and only once and returns it to the client. The constructor method 'Singleton()' is private and thus not visible to the client. The Design Patterns book lists the following benefits:
2828
2929- Controlled access to sole instance
3030- Reduced namespace
3131- Permits refinement of operations and representation
3232- Permits variable number of instances (extend the class to allow a controlled number of instances if designer wants to allow such a situation)
3333- More flexible than class operations
3434
3535## The Singleton Client
3636
3737The following program would be typical use of a singleton.
3838
3939``` pascal
4040program TrueSingleton;
4141
4242 {$mode objfpc}{$H+}
4343
4444 uses
4545 {$IFDEF UNIX}{$IFDEF UseCThreads}
4646 cthreads,
4747 {$ENDIF}{$ENDIF}
4848 Classes, Singleton2
4949 { you can add units after this };
5050
5151 {$R TrueSingleton.res}
5252 var
5353 s1, s2: TSingleton;
5454
5555 begin
5656 s1:= TSingleton.GetInstance;
5757 s1.name := 'one';
5858 writeln('name of s1: '+s1.name);
5959
6060 s2:= TSingleton.GetInstance;
6161 s2.name := 'two';
6262
6363 writeln('name of s1: '+s1.name);
6464 writeln('name of s2: '+s2.name);
6565 //writeln('name of singleton: ' + Singleton.name);
6666 readln;
6767 end.
6868```
6969
7070That is, if the singleton would work according to the pattern. The *GetInstance* method is a class method that returns the only available instance. We will help our user, the programmer, if the constructor *Create* would not show up in the code completion at all. This helps our users to remember that they should use *GetInstance*. A problem here however is that FreePascal, in contrast to other languages, doesn't require a specific name as constructor. *Init* is just as good a name for a constructor as *Create* is.
7171
7272The correct output will look like this:
7373
74-`name of s1: one`\
75-`name of s1: two`\
76-`name of s2: two`
74+```text
75+name of s1: one
76+ name of s1: two
77+ name of s2: two
78+```
7779
7880When the correct output is produced, `Singleton.GetInstance` will return the singleton instance and the name of both `s1` and `s2` will always be the same. The wrong output will look like this:
7981
80-`name of s1: one`\
81-`name of s1: one`\
82-`name of s2: two`
82+```text
83+name of s1: one
84+ name of s1: one
85+ name of s2: two
86+```
8387
8488When the wrong output is produced, a second instance is created that has its own name.
8589
8690## Nice Pattern, Don't Use It
8791
8892Or at least think it over before you use it. There are many reasons to not use a singleton. Really, there are more reasons not to use a singleton than there are reasons to use a singleton. See the [Drawbacks and Reference sections](https://en.wikipedia.org/w/index.php?title=Singleton_pattern&oldid=397293289#Drawbacks) of an old version of the WikiPedia article discussing singletons. The main reasons:
8993
9094- Difficult to test. Because of its nature, singletons are hard to replace for testing.
9195- Singletons make dependencies unclear. Although the singleton comes from another unit, you cannot see in the interface of your object that the singleton is used. Well, the **uses** section gives a clue, but that doesn't say *where* exactly it is used.
9296
9397Singletons are commonly used for shared resources or 'engines':
9498
9599- Printers
96100- Databases
97101- Loggers
98102
99103To avoid the use of too many singletons, try to avoid them and use only one in your whole application. For example, you may want to create a toolbox (aka [[http://martinfowler.com/eaaCatalog/registry.html Registry]]) for your application. Now the toolbox knows the printer, database or logger and your code queries the toolbox for instances. Your code depends on the toolbox and the toolbox depends on the resources that can be queried. This reduces the dependencies from a lot of singleton to only one singleton.
100104
101105Another idea is to use [[http://www.theserverside.com/news/1321158/A-beginners-guide-to-Dependency-Injection Dependency Injection]]. If an object 'B' needs another object 'A' to function properly, then hand the object 'A' to the constructor of the class 'B'. This at least makes clear that the class B depends on A in the interface.
102106
103107To improve testing of your code, you may want to have your singletons implement an interface. The *GetInstance* method or function may then return an instance that conforms to the interface. Depending on whatever (compilation directives etc.) the *GetInstance* method can return the 'real' object or a mock-up.
104108
105109In the rest of this article I discuss how to create a singleton.
106110
107111# Going Global
108112
109113## In Your (Inter)Face
110114
111115In Free Pascal it is quite common to define a global variable for the Singleton pattern. All through the source code of FreePascal and Lazarus you will find examples of this. The idea is to create an instance at initialization of the unit file and then use it when needed. The client programmer should just know that there is a global instance and that that global instance should be used. Every programmer writes and reads full documentation, so usually this is no problem.
112116
113117``` pascal
114118unit GlobalVariableSingleton;
115119
116120 {$mode objfpc}{$H+}
117121
118122 interface
119123
120124 type
121125 TSingleton = class
122126 name: String;
123127 constructor create;
124128 end;
125129
126130 var
127131 Singleton: TSingleton = nil;
128132
129133 implementation
130134 {* Something happens out here *}
131135
132136 initialization
133137 Singleton := TSingleton.Create;
134138
135139 end.
136140```
137141
138142When this unit is loaded, the singleton is instantiated and can be used. The initialization takes place when the program is started, so the singleton is always present. This violates the reduction of namespace, the namespace is polluted by a global variable that is waiting for use. Even if the programmer is not interested in the instance, but is only interested in other functionality in your unit, the instance is created and will use memory. On the other hand, we wanted to have a singleton so that we would use it right? There is no probability involved, we will use the instance. So, why not create the instance when we startup the application? With the above definition of a global variable the instantiation is not controlled. Any programmer can still instantiate the TSingleton. This can be improved with documentation and a constructor that warns against instantiation after the global variable is created. Something like the following:
139143
140144``` pascal
141145constructor TSingleton.Create;
142146 begin
143147 If Assigned(Singleton) then
144148 Raise Exception.Create('Please use the global variable Singleton');
145149 inherited Create;
146150 end;
147151```
148152
149153However, such a constructor only warns at run time and doesn't help at design time. An alternative to the if statement could be an assert. With an assert the detection would be moved to test time, which – as you know - we all do and happens far before run time. However, an assert doesn't even help at run time since the asserts are not linked in for the run time application. I agree, it does seem to happen that not all code is always tested. In the given constructor the program at least breaks due to an unhandled exception. The programmer of your client will probably work around that annoyance with a `try ... except` statement. Even though programmers can work around the issue, their code doesn't work so why should they? The global variable is not a singleton at design time, the constructor will still show up. However, it will certainly be a singleton at run time. The typical client code is:
150154
151155``` pascal
152156program TrueSingleton;
153157
154158 {$mode objfpc}{$H+}
155159
156160 uses
157161 {$IFDEF UNIX}{$IFDEF UseCThreads}
158162 cthreads,
159163 {$ENDIF}{$ENDIF}
160164 Classes, GlobalVariableSingleton
161165 { you can add units after this };
162166
163167 {$R TrueSingleton.res}
164168 var
165169 s1, s2: TSingleton;
166170
167171 begin
168172 s1:= Singleton;
169173 s1.name := 'one';
170174 writeln('name of s1: '+s1.name);
171175
172176 s2:= Singleton;
173177 s2.name := 'two';
174178
175179 writeln('name of s1: '+s1.name);
176180 writeln('name of s2: '+s2.name);
177181 //writeln('name of singleton: ' + Singleton.name);
178182 readln;
179183 end.
180184```
181185
182186Of course, instead of assigning the global variable to a local variable you can also use the global variable directly.
183187
184188## Up Your Implementation
185189
186190Notice how in the *GlobalVariableSingleton* unit the global variable is defined in the interface section. This is what makes the variable *Singleton* a global variable. If you put the variable in the implementation section, the variable will only be available for code in the implementation section. As such, a variable defined in the implementation section acts similar to a class or package variable. The implementation variable can be used by all the code in the unit but not outside that unit. The interface variable is public, can be used inside and outside the unit. This is used in the following code.
187191
188192``` pascal
189193unit GlobalFunctionSingleton;
190194
191195 {$mode objfpc}{$H+}
192196
193197 interface
194198
195199 uses
196200 Classes, SysUtils;
197201 type
198202 TSingleton = class
199203 public
200204 name : String;
201205 constructor Create;
202206 end;
203207
204208 function GetSingleton : TSingleton;
205209
206210 implementation
207211 var
208212 Singleton : TSingleton = nil;
209213
210214 constructor TSingleton.Create;
211215 begin
212216 assert(Singleton=nil, 'illegal recreation of Singleton.');
213217 inherited Create;
214218 Singleton := self;
215219 end;
216220
217221 function GetSingleton : TSingleton;
218222 Begin
219223 If(Singleton = nil) then
220224 raise Exception.Create('Singleton not created during initialization.');
221225 Result := Singleton;
222226 end;
223227
224228 initialization
225229 Singleton := TSingleton.Create;
226230 end.
227231```
228232
229233In this case, the singleton instance is not a global variable (it is defined in the implementation section) and cannot be used outside the implementation section. The *GetSingleton* function however can be used outside the unit. But in contrast to the pattern diagram, it is not a class method but a good old global function. The advantage over the previous implementation is that the *GetSingleton* function can contain more functionality than just returning the one instance. For example, the function could be used to hand out instances from a pool of singletons. The client code is as follows:
230234
231235``` pascal
232236program TrueSingleton;
233237
234238 {$mode objfpc}{$H+}
235239
236240 uses
237241 {$IFDEF UNIX}{$IFDEF UseCThreads}
238242 cthreads,
239243 {$ENDIF}{$ENDIF}
240244 Classes, GlobalFunctionSingleton
241245 { you can add units after this };
242246
243247 {$R TrueSingleton.res}
244248 var
245249 s1, s2: TSingleton;
246250
247251 begin
248252 s1:= GetSingleton;
249253 s1.name := 'one';
250254 writeln('name of s1: '+s1.name);
251255
252256 s2:= GetSingleton;
253257 s2.name := 'two';
254258
255259 writeln('name of s1: '+s1.name);
256260 writeln('name of s2: '+s2.name);
257261 //writeln('name of singleton: ' + Singleton.name);
258262 readln;
259263 end.
260264```
261265
262266It works, but I have not seen this applied in any source code.
263267
264268# Classy Implementation
265269
266270## Simple Singleton
267271
268272The following code presents a very simple singleton.
269273
270274``` pascal
271275unit Singleton1;
272276
273277 {$mode objfpc}{$H+}
274278
275279 interface
276280
277281 type
278282 TSingleton = class
279283 name: String;
280284 constructor create;
281285 end;
282286
283287 implementation
284288
285289 var
286290 Singleton: TSingleton = nil;
287291
288292 constructor TSingleton.Create;
289293 begin
290294 if not(assigned(Singleton)) then begin
291295 inherited;
292296 (*... do initializations ...*)
293297 Singleton := self;
294298 end else begin
295299 self := Singleton;
296300 end;
297301 end;
298302
299303 end.
300304```
301305
302306In the *Singleton1* unit, notice the following:
303307
304308- The Singleton variable is defined in the **implementation** section. This makes the variable invisible outside the unit.
305309- A public constructor is used.
306310
307311Free Pascal doesn't allow for class variables and class properties. Only procedures and functions can be modified with the class keyword. Defining the 'static' variable in the implementation section is the closest we can get to a static variable. At initialization this variable is set to **nil**, so no memory is used yet. Although this implementation works, the `self := Singleton;` bugs me. I didn't try it, but I assume this allows for memory leaks. Even if it doesn't allow for memory leaks, it just doesn't look right.
308312
309313## Why It Is Different In Pascal
310314
311315Then why not implement the singleton just like it is shown in the Pattern diagram? Well, here we go:
312316
313317``` pascal
314318unit Singleton2;
315319
316320 {$mode objfpc}{$H+}
317321
318322 interface
319323
320324 uses
321325 Classes, SysUtils;
322326
323327 type
324328 TSingleton = class
325329 private
326330 constructor Create;
327331 public
328332 name: String;
329333 class function GetInstance : TSingleton;
330334 end;
331335
332336 implementation
333337 var
334338 Singleton : TSingleton = nil;
335339
336340 constructor TSingleton.Create;
337341 begin
338342 inherited Create;
339343 end;
340344
341345 class function TSingleton.GetInstance : TSingleton;
342346 begin
343347 if Singleton = nil then
344348 Singleton := TSingleton.Create;
345349 Result := Singleton;
346350 end;
347351
348352 end.
349353```
350354
351355The problem with the *Singleton2* unit is that the program will work with the following client code:
352356
353357``` pascal
354358program TrueSingleton;
355359
356360 {$mode objfpc}{$H+}
357361
358362 uses
359363 {$IFDEF UNIX}{$IFDEF UseCThreads}
360364 cthreads,
361365 {$ENDIF}{$ENDIF}
362366 Classes, Singleton2
363367 { you can add units after this };
364368
365369 {$R TrueSingleton.res}
366370 var
367371 s1, s2: TSingleton;
368372
369373 begin
370374 s1:= TSingleton.Create;
371375 s1.name := 'one';
372376 writeln('name of s1: '+s1.name);
373377
374378 s2:= TSingleton.Create;
375379 s2.name := 'two';
376380
377381 writeln('name of s1: '+s1.name);
378382 writeln('name of s2: '+s2.name);
379383 //writeln('name of singleton: ' + Singleton.name);
380384 readln;
381385 end.
382386```
383387
384388It is difficult to see the problem. In the *Singleton2* unit we made the constructor private. Run the client code, and the compiler complains about the constructor not being public, but after that the program works and shows that the code doesn't work as a singleton. Two different instances will be created. We learn from this that although we reduced the visibility of the constructor, the *TObject.Create* constructor is still visible.
385389
386390## The 'constructor should be public' Singleton
387391
388392A *small* change makes a big difference:
389393
390394``` pascal
391395unit Singleton3;
392396
393397 {$mode objfpc}{$H+}
394398
395399 interface
396400
397401 uses
398402 Classes, SysUtils;
399403
400404 type
401405 TSingleton = class
402406 private
403407 constructor Init;
404408 public
405409 name: String;
406410 class function Create: TSingleton;
407411 end;
408412
409413 implementation
410414 var
411415 Singleton : TSingleton = nil;
412416
413417 constructor TSingleton.Init;
414418 begin
415419 inherited Create;
416420 end;
417421
418422 class function TSingleton.Create: TSingleton;
419423 begin
420424 if Singleton = nil then
421425 Singleton := TSingleton.Init;
422426 Result := Singleton;
423427 end;
424428
425429 end.
426430```
427431
428432The *Init* constructor provides us with the constructor we need to avoid illegally hiding the TObject constructor. The *Init* constructor is also private. The *Create* **function** hides the *TObject.Create* constructor. This code works. Using the above we have controlled access to the singleton. We also do not pollute the namespace with global variables. We can create additional methods as much as we want. Also, if we declare an array of singletons in the implementation section we can provide additional, but limited instances of the singleton. And, we do not need additional static methods other than the *Create* function. All benefits of the singleton pattern are thus achieved. Typical client code now needs to look like the following:
429433
430434``` pascal
431435program TrueSingleton;
432436
433437 {$mode objfpc}{$H+}
434438
435439 uses
436440 {$IFDEF UNIX}{$IFDEF UseCThreads}
437441 cthreads,
438442 {$ENDIF}{$ENDIF}
439443 Classes, Singleton3
440444 { you can add units after this };
441445
442446 {$R TrueSingleton.res}
443447 var
444448 s1, s2: TSingleton;
445449
446450 begin
447451 s1:= TSingleton.Create;
448452 s1.name := 'one';
449453 writeln('name of s1: '+s1.name);
450454
451455 s2:= TSingleton.Create;
452456 s2.name := 'two';
453457
454458 writeln('name of s1: '+s1.name);
455459 writeln('name of s2: '+s2.name);
456460 //writeln('name of singleton: ' + Singleton.name);
457461 readln;
458462 end.
459463```
460464
461465Notice how this program uses the *Create* method, not the *GetInstance* method. But, look at the class definition again. *Create* is not a constructor it is a class method that returns the singleton instance. *Init* is the constructor.
462466
463467## Hide That For Me
464468
465469When compiling, the compiler warns that the constructor is not public. So, now you are warned. You can choose to ignore the warning, because the code is really what you want. You can also suppress the warning. The message code for the 'Constructor should be public' warning is 3018. To suppress the warning add `-vm3018` to the command line of the compiler. In Lazarus you can deselect the message {From the **Project** menu, choose **Project Options**. Then, in the **Options for Project:** dialog, open the **Compiler Options** branch in the navigation pane and click **Messages**. Now deselect '(W)Constructor should be public' in the compiler messages list.}
466470
467471# Discussion Of The Options
468472
469473In this part we will pay attention to some of the discussions.
470474
471475## Reducing the visibility of the constructor
472476
473477Of course there is a reason why a constructor should be public. The Free Pascal compiler thus gives a warning when the constructor is made private. However, why does FreePascal give the warning? Other programming languages allow private constructors without a problem. Apart from that it is bad Pascal programming behavior, I don't know the answer. Maybe, since it is a warning, the reasoning may be that if the constructor is not public, then there is no way to create the object and what is the use of a class if you cannot make an object out of it? To sum things up, the argument is as follows:
474478
475-`The reason you can't lower the visibility of the constructor or any`\
476-`method for that matter... A class interface (implementation section) ,`\
477-`even for TObject as in your example, is a contract of how you can use`\
478-`that class and what is available to you.  By lowering the visibility`\
479-`of a method or constructor in a descendant class, you are breaking the`\
480-`contract previously defined. This is a BIG no-no, hence the reason it`\
481-`is not allowed.`
479+``` pascal
480+The reason you can't lower the visibility of the constructor or any
481+method for that matter... A class interface (implementation section) ,
482+even for TObject as in your example, is a contract of how you can use
483+that class and what is available to you. By lowering the visibility
484+of a method or constructor in a descendant class, you are breaking the
485+contract previously defined. This is a BIG no-no, hence the reason it
486+is not allowed.
487+```
482488
483489## Design Time Help vs. Run Time Breaking
484490
485491The following arguments may lead you to choose the Singleton3 unit as example implementation:
486492
487493- The Singleton3 provides design time guidance. Possible alternatives that are more in the spirit of Pascal give run time break downs, or at best testing time messages. Design time guidance is preferred in my opinion.
488494- If you want to avoid multiple instantiation of the class, then why not provide design time help to the client programmer.
489495- In other programming languages it is not bad programming behavior, so FreePascal must have a very good reason to avoid it.
490496- Reducing the visibility of any method of a class should not be allowed except for the constructor.
491497
492498## The pattern is not followed
493499
494500Yes, the pattern is not closely followed. The constructor is called *Init* while in FreePascal there is the convention to call the constructor *Create*. Then on top of that name *Create* is used for the static function instead of the name *GetInstance*. The following arguments are in favor of the most likable implementation:
495501
496502- The intent of the pattern is followed and the benefits achieved.
497503- The code is quite nice and well behaved. There are no run-time breaks built in and there are no doubtful constructs in the code.
498504- Some compromises had to be made to make the singleton work in FreePascal.
499505
500506## The implementations have a problem with multi-threading and synchronization
501507
502508I never saw a good discussion about this, but in discussions about singletons in various programming languages programmers go far to make their singleton multi-threaded and synchronized and a number of other things. The singleton implementations given in this article are not optimized for that.
503509
504510## The singleton class implementation has a problem with platform independence
505511
506512A singleton can never have descendants. What should happen when a descendant class calls **inherited Create**? Also it would be quite wrong to make the singleton descend from anything else but TObject. Now consider platform independence. Look at FreePascal sources where a global variable is used for a printer or whatever central resource. These global variables are by no exception made in the platform specific units, the shared functionality is written in a platform independent unit. Consider how this should be done with a singleton class. (I'll wait here until you find out that a hierarchy of singletons will inevitably cause a mess and will not allow for platform independent code.) Now that you are convinced we can easily say that the singleton class cannot be used with shared functionality, repeating singleton functionality for all platform implementations will cause a maintenance mess.
507513
508514# Conclusion
509515
510516Yes, singletons are possible! Even in FreePascal. But, singletons are not a very good idea in platform independent FreePascal code. Whether you use a class or a global variable, there is no *perfect* implementation of a singleton.
511517
512518---
513519*From the Free Pascal wiki, page "Singleton Pattern", as it stood on 2020-05-08 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
514520Category: Design Patterns
515521Category: FPC
516522Category: Pascal
517523Category: Tutorials

Back to history