Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2006-12

Implementing a true Singleton - Can we decrease the visibility of a method?

32 messages · 12 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Bottom line: How can we hide the constructor of a class? As far as I can see you cannot decrease the visibility of a method compared to it's inherited class. Why shouldn't we be allowed to? C++, C# does!

I found this by trying to implement a True Singleton in Free Pascal / Delphi. For those that don't know, a Singleton is a Design Pattern that allows only one instance of a class. It seems it is impossible to do in Free Pascal / Delphi. :-(

See attached code for a demonstration of the problem.

And here is the output. The first two '>> PrintData' sections are correct and use the singleton as it should be used. The third '>> PrintData' section is by declaring a new variable of TSingleton and creating it.

The problem is even though the constructor is declared in the protected section, Free Pascal just gives a compiler warning and it stays public. What is the reason why we may not decrease visibility of methods or properties? Couldn't we add this feature to Free Pascal? Or at least in the ObjFPC mode!

Is there another way of implementing a true singleton in Free Pascal, maybe using some other language construct.

----------------------- START Output --------------- [graemeg-linux] singleton > ./singtest

> PrintData

hello world
---------

> PrintData

hello world
hello world 2
---------

> PrintData

----------------------- END Output ---------------

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Vincent Snijders
to Graeme Geldenhuys
Graeme Geldenhuys wrote 21 lines
Bottom line: How can we hide the constructor of a class? As far as I can see you cannot decrease the visibility of a method compared to it's inherited class. Why shouldn't we be allowed to? C++, C# does! I found this by trying to implement a True Singleton in Free Pascal / Delphi. For those that don't know, a Singleton is a Design Pattern that allows only one instance of a class. It seems it is impossible to do in Free Pascal / Delphi. :-( See attached code for a demonstration of the problem. And here is the output. The first two '>> PrintData' sections are correct and use the singleton as it should be used. The third '>> PrintData' section is by declaring a new variable of TSingleton and creating it. The problem is even though the constructor is declared in the protected section, Free Pascal just gives a compiler warning and it stays public. What is the reason why we may not decrease visibility of methods or properties? Couldn't we add this feature to Free Pascal? Or at least in the ObjFPC mode!

Maybe I am analyzing your output wrong, but to me it seems as if the contructor of TObject is called in the third case. printdata seems to print an empty text.

So the protected contructor is unreachable, but the public constructor in TObject remains public.

Vincent

Graeme Geldenhuys
to Vincent Snijders
Vincent Snijders wrote 5 lines
Maybe I am analyzing your output wrong, but to me it seems as if the contructor of TObject is called in the third case. printdata seems to print an empty text. So the protected contructor is unreachable, but the public constructor in TObject remains public.

That's correct, which is even worse. It gives us a half-baked object. fData is never initialized. Putting a writeln() statement inside TSingleton.Create shows that on the 3rd instance it is never executed.

[graemeg-linux] singleton > ./singtest

> Tsingleton.Create > PrintData

hello world
---------

> Tsingleton.Create > PrintData

hello world
hello world 2
---------

> PrintData
Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Vincent Snijders
to Graeme Geldenhuys
Graeme Geldenhuys wrote 14 lines
On 12/8/06, Vincent Snijders wrote: > Maybe I am analyzing your output wrong, but to me it seems as if the > contructor of > TObject is called in the third case. printdata seems to print an empty > text. > > So the protected contructor is unreachable, but the public constructor > in TObject > remains public. That's correct, which is even worse. It gives us a half-baked object. fData is never initialized. Putting a writeln() statement inside TSingleton.Create shows that on the 3rd instance it is never executed.

I think the solution is to create a public constructor which throws an NotImplemented exception or something like that.

Then you create a protected (or private) constructor constructor CreateSingletonInstance;
which is accessible only in that unit.

Note: instead of making function GetSingleton : TSingleton; a global function you could make it class function GetInstance too.

Vincent

Graeme Geldenhuys
to Vincent Snijders
Vincent Snijders wrote
I think the solution is to create a public constructor which throws an NotImplemented exception or something like that.

Ok, that works, or at least stops a developer from trying to create a instance directly. In the exception message, I mention the correct function they should have used.

Note: instead of making function GetSingleton : TSingleton; a global function you could make it class function GetInstance too.

Yes I know, thanks. But I prefer to use the function, as it is less typing, especially when the class name is lengthy. I also normally prefix it with a 'g' to show it is a global singleton function.

gLog
vs
TLogToFile.GetSingleton

When you use singletons a lot (as I do), less typing is better. :)

PS:
I still don't know why we can't decrease visibility in Free Pascal. Is there some internal language design that prevents it?

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Jonas Maebe
to Graeme Geldenhuys
Graeme Geldenhuys wrote
I still don't know why we can't decrease visibility in Free Pascal. Is there some internal language design that prevents it?

At least Borland explicitly says you cannot do that: http://info.borland.com/techpubs/delphi/delphi5/oplg/classes.html

"You can increase the visibility of a member in a descendant class by redeclaring it, but you cannot decrease its visibility. For example, a protected property can be made public in a descendant, but not private. Moreover, published members cannot become public in a descendant class."

Jonas

TOndrej
to Graeme Geldenhuys: Ok, that works, or at least stops a developer from trying to create a instance directly. …
Graeme Geldenhuys wrote
I still don't know why we can't decrease visibility in Free Pascal. Is there some internal language design that prevents it?

A class definition (or at least its parts visible from outside) can be understood as a kind of contract. If you have a class TDog with a public property Tail then, by definition, any TDog descendant (TBulldog, TLabrador, TDingo etc.) must have the public property Tail. Otherwise they wouldn't be TDog but something else, again by definition.

I'm not even sure if there is a language which allows demoting visibility of inherited class members. It would seem odd to me. Just my 2c, of course. ;-)

HTH
TOndrej

Graeme Geldenhuys
to TOndrej
TOndrej wrote 7 lines
On 12/8/06, Graeme Geldenhuys wrote: > I still don't know why we can't decrease visibility in Free Pascal. > Is there some internal language design that prevents it? A class definition (or at least its parts visible from outside) can be understood as a kind of contract. If you have a class TDog with a public property Tail then, by definition, any TDog descendant

I understand your example and that makes sense, but would be handy in certain cases to change it.

I'm not even sure if there is a language which allows demoting visibility of inherited class members. It would seem odd to me. Just my 2c, of course. ;-)

C++, C#, VB.Net are three I know of. I think Java also allows it.

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Jonas Maebe
to Graeme Geldenhuys
Graeme Geldenhuys wrote 5 lines
> I'm not even sure if there is a language which allows demoting > visibility of inherited class members. It would seem odd to me. Just > my 2c, of course. ;-) C++, C#, VB.Net are three I know of.

http://msdn2.microsoft.com/en-us/library/ms182332(VS.80).aspx

Quote:

"You should not change the access modifier for inherited members."

So it's possible but discouraged, and they give warnings (and sometimes errors) for it with the recommendation "Do not exclude a warning from this rule."

As far as I understand the text on that page, the only case where it's considered "safe" is if the the method/class is declared "final". We do not have final methods/classes in Object Pascal, and such final methods/classes are often considered a cause of problems in themselves (because you can bet sooner or latter someone will have some need to override/inherit anyway).

Jonas

Graeme Geldenhuys
to Jonas Maebe
Jonas Maebe wrote 7 lines
Quote: "You should not change the access modifier for inherited members." So it's possible but discouraged, and they give warnings (and sometimes errors) for it with the recommendation "Do not exclude a warning from this rule."

There is a lot of things in life we shouldn't do, but we do. :-) At least give us the choice, maybe via a compiler directive and keep the compiler warning in place. That way we can use it responsibly when required, as in the case of implementing a true singleton. I'm sure there are more examples. As it stands currently (my sample singleton code) the developer can still screw up by creating a new instance instead of going through the global function.

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Vincent Snijders
to Graeme Geldenhuys
Graeme Geldenhuys wrote 17 lines
On 12/8/06, Jonas Maebe wrote: > Quote: > > "You should not change the access modifier for inherited members." > > So it's possible but discouraged, and they give warnings (and > sometimes errors) for it with the recommendation "Do not exclude a > warning from this rule." There is a lot of things in life we shouldn't do, but we do. :-) At least give us the choice, maybe via a compiler directive and keep the compiler warning in place. That way we can use it responsibly when required, as in the case of implementing a true singleton. I'm sure there are more examples. As it stands currently (my sample singleton code) the developer can still screw up by creating a new instance instead of going through the global function.

I think it cannot be prevented.

Suppose you could hide the constructor and TSingleton.Create was not visible, I still could create a TSingleton object and call the TObject.Create on it.

var
   Singleton1, Singleton2: TSingleton;
begin
   Singleton1 := TSingleton.CreateInstance;
   TObject(Singleton1).Create;
   Singleton2 := TSingleton.CreateInstance;
   TObject(Singleton).Create;
   // now there are two Singleton objects.
end.
Jonas Maebe
to Graeme Geldenhuys: There is a lot of things in life we shouldn't do, but we do. :-) At least give us the…
Graeme Geldenhuys wrote
There is a lot of things in life we shouldn't do, but we do. :-) At least give us the choice, maybe via a compiler directive and keep the compiler warning in place. That way we can use it responsibly when required,

This is a generic argument which you can use in support of pretty much any relaxing of semantic/syntax rules.

as in the case of implementing a true singleton. I'm sure there are more examples. As it stands currently (my sample singleton code) the developer can still screw up by creating a new instance instead of going through the global function.

This particular issue is caused by the fact that in Delphi-style Object Pascal classes automatically inherit from TObject, which has a public constructor. And if you override the constructor with your own, they no longer can do that either (although it's obviously a run time and not compile time check).

One thing that could be changed is the compile so that you get a compile-time error if you try

type
   tc = class
     constructor create; virtual; abstract;
   end;
var
   c: tc;
begin
   c := tc.create
end.

(currently this compiles with only a warning about the fact that tc has abstract methods)

It would however still only give a run time error if you'd instead do

type
   tc = class
     constructor create; virtual; abstract;
   end;
  ttc = class of tc;
var
   cc: ttc;
   c: tc;
begin
   cc := tc;
   c := cc.create;
end.

Jonas

TOndrej
to Graeme Geldenhuys: I understand your example and that makes sense, but would be handy in certain cases to…
Show quoted text 5 lines
> I'm not even sure if there is a language which allows demoting > visibility of inherited class members. It would seem odd to me. Just > my 2c, of course. ;-) C++, C#, VB.Net are three I know of. I think Java also allows it.

In these languages, AFAIK, it's allowed, the compiler generates a warning, but the visibility does not actually change. You would still be able to access the member, if not directly on a variable of the descendant type then certainly by typecasting to the ancestor type.

HTH
TOndrej

Steve Williams
to Graeme Geldenhuys: Bottom line: How can we hide the constructor of a class? As far as I can see you cannot…
I found this by trying to implement a True Singleton in Free Pascal / Delphi. For those that don't know, a Singleton is a Design Pattern that allows only one instance of a class. It seems it is impossible to do in Free Pascal / Delphi. :-(

Try this.
http://bdn.borland.com/article/22576

Sly This message and its attachments may contain legally privileged or confidential information. This message is intended for the use of the individual or entity to which it is addressed. If you are not the addressee indicated in this message, or the employee or agent responsible for delivering the message to the intended recipient, you may not copy or deliver this message or its attachments to anyone. Rather, you should permanently delete this message and its attachments and kindly notify the sender by reply e-mail. Any content of this message and its attachments, which does not relate to the official business of the sending company must be taken not to have been sent or endorsed by the sending company or any of its related entities. No warranty is made that the e-mail or attachment(s) are free from computer virus or other defect.
Matt Emson
to Jonas Maebe: At least Borland explicitly says you cannot do that:…
Show quoted text 7 lines
On 8 dec 2006, at 10:55, Graeme Geldenhuys wrote: > I still don't know why we can't decrease visibility in Free Pascal. > Is there some internal language design that prevents it? At least Borland explicitly says you cannot do that: http://info.borland.com/techpubs/delphi/delphi5/oplg/classes.html

Delphi 5 onwards generates a hint for each method that is of a lower visibility thatn its ancestors implementation.

I've used the following to implement a singleton before:

unit x;
interface
type
  ISingleton = interface [-----GUID GOES HERE-----]
    procedure SingletonAction;
  end;
var
  MySingleton: ISingleton;
implementation
type
  TSingleton = class(TInterfacedObject, ISingleton)
  private
     procedure SingletonAction;
  end;
   procedure TSingleton .SingletonAction;
   begin
       [....]
   end;
initialization
   MySingleton := TSingleton.Create;
finalization
    MySingleton := nil;
end.
Michael Van Canneyt
to Steve Williams: Try this. http://bdn.borland.com/article/22576 Sly This message and its attachments may…
Steve Williams wrote 7 lines
> I found this by trying to implement a True Singleton in Free Pascal / > Delphi. For those that don't know, a Singleton is a Design Pattern > that allows only one instance of a class. It seems it is impossible > to do in Free Pascal / Delphi. :-( Try this. http://bdn.borland.com/article/22576

Maybe we should include an implementation in FPC by default ?

Michael.

Andreas Berger
to Graeme Geldenhuys: I understand your example and that makes sense, but would be handy in certain cases to…
Graeme Geldenhuys wrote 11 lines
On 12/8/06, TOndrej wrote: > On 12/8/06, Graeme Geldenhuys wrote: > > I still don't know why we can't decrease visibility in Free Pascal. > > Is there some internal language design that prevents it? > > A class definition (or at least its parts visible from outside) can be > understood as a kind of contract. If you have a class TDog with a > public property Tail then, by definition, any TDog descendant I understand your example and that makes sense, but would be handy in certain cases to change it.

A TBoxer could be considered a TDog without a tail :)

Show quoted text 6 lines
> I'm not even sure if there is a language which allows demoting > visibility of inherited class members. It would seem odd to me. Just > my 2c, of course. ;-) C++, C#, VB.Net are three I know of. I think Java also allows it.

Yes, but that causes other problems. I worked for a time for a company that wrote programs for aeronautical equipment. In these cases the above mentioned languages could not be used. C was ok, and C++ could only be used if you followed very strict rules (and a lint program to guarantee you were following the rules). Pascal however had far fewer restrictions (almost none if I remember correctly). Modula-2 could be freely used. If we relax the Pascal rules we will end up with a non-secure language like the above.

Marc Santhoff
to Graeme Geldenhuys: Bottom line: How can we hide the constructor of a class? As far as I can see you cannot…
Graeme Geldenhuys wrote 10 lines
Bottom line: How can we hide the constructor of a class? As far as I can see you cannot decrease the visibility of a method compared to it's inherited class. Why shouldn't we be allowed to? C++, C# does! I found this by trying to implement a True Singleton in Free Pascal / Delphi. For those that don't know, a Singleton is a Design Pattern that allows only one instance of a class. It seems it is impossible to do in Free Pascal / Delphi. :-( See attached code for a demonstration of the problem.

One working solution is to use a global var. This is bad but acceptable for a singleton imo. If would be nice if the variable could be hidden. Smth like this:

...
var
	_mySingleton: TSingleton;
constructor TSingleton.create;
begin
	if not(assigned(_mySingleton)) then
	begin
		inherited;
		... do initializations ...
		_mySingleton := self;
	end;
end;
initilization
	_mySingleton := NIL;
end.

HTH,
Marc

Daniël Mantione
to Micha Nelissen

Op Fri, 8 Dec 2006, schreef Micha Nelissen:

Btw, I think singletons are nonsense too. Why is a global variable evil, and a singleton class not ?

Well, a singleton can hide and/or protect its private data.

Actually, a unit is a singleton. The procedures are the methodes, the interface declares the public methode and the implementation the private methods. The constructor is the initialization section and the destructor the finalization section.

But, in pure OOP the unit concept does not exist. I interpret the singleton as the OOP equivalent of the unit.

Daniël

Micha Nelissen
to Daniël Mantione
Daniël Mantione wrote 7 lines
Op Fri, 8 Dec 2006, schreef Micha Nelissen: > Btw, I think singletons are nonsense too. Why is a global variable evil, > and a singleton class not ? Well, a singleton can hide and/or protect its private data.

Not more than a global variable of the same class type ?

Micha

Dean Zobec
to Micha Nelissen: NewInstance/FreeInstance is what I would have recommended as well. How ? The article…
Show quoted text 11 lines
>> Try this. >> http://bdn.borland.com/article/22576 NewInstance/FreeInstance is what I would have recommended as well. > Maybe we should include an implementation in FPC by default ? How ? The article works as-is AFAIK. Btw, I think singletons are nonsense too. Why is a global variable evil, and a singleton class not ?

You are right, beware of singletons. Being a simple pattern to implement it's often misused and sometimes creates more problems than it solves, it's a global variable after all, and you should put an extra effort to try to avoid it as you would avoid a global variable.

It was one of the things I've learnt through unit testing, using a singleton breaks the independency between tests, because the singleton carries state with it that lasts as long as the program runs. In this case thinking about how to make tests independent of each other and trying to
introduce a mock object for the singleton, you can get rid of it in a lot of cases.
The best thing is usually to think about how we can substitute a singleton in the client class with a parameter in the constructor of the client class.
See this article for further explanation:
http://www-128.ibm.com/developerworks/library/co-single.html

Regards,
Dean

Steve Williams
to Michael Van Canneyt: Maybe we should include an implementation in FPC by default ? Michael.
Show quoted text 9 lines
> > I found this by trying to implement a True Singleton in Free Pascal / > > Delphi. For those that don't know, a Singleton is a Design Pattern > > that allows only one instance of a class. It seems it is impossible > > to do in Free Pascal / Delphi. :-( > > Try this. > http://bdn.borland.com/article/22576 Maybe we should include an implementation in FPC by default ?

That shouldn't be difficult. The implementation given in that article is quite simple and effective.

Sly This message and its attachments may contain legally privileged or confidential information. This message is intended for the use of the individual or entity to which it is addressed. If you are not the addressee indicated in this message, or the employee or agent responsible for delivering the message to the intended recipient, you may not copy or deliver this message or its attachments to anyone. Rather, you should permanently delete this message and its attachments and kindly notify the sender by reply e-mail. Any content of this message and its attachments, which does not relate to the official business of the sending company must be taken not to have been sent or endorsed by the sending company or any of its related entities. No warranty is made that the e-mail or attachment(s) are free from computer virus or other defect.
Graeme Geldenhuys
to Marc Santhoff: One working solution is to use a global var. This is bad but acceptable for a singleton…
Marc Santhoff wrote
One working solution is to use a global var. This is bad but acceptable for a singleton imo. If would be nice if the variable could be hidden.

This is kinda what I have been using all along, except, I have a function, that creates the instance when used for the first time. I call it the Lazy mans Singleton. It works perfectly, if the developer knows about the global function! Otherwise, they might still try and create a instance of the class, which is what I am trying to prevent.

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Graeme Geldenhuys
to Micha Nelissen: NewInstance/FreeInstance is what I would have recommended as well. How ? The article…
Micha Nelissen wrote 6 lines
Michael Van Canneyt wrote: >> Try this. >> http://bdn.borland.com/article/22576 NewInstance/FreeInstance is what I would have recommended as well.

I haven't actually looked at that one yet, I looked at one based on that, but allows for inheritance on a TSingleton base class. Running it with FPC and Heaptrc unit, I found memory leaks. I'll try the one from Borland.

This is the one I tried as well. Quite nice, except for the memory leaks at the 'inherited' call.
http://www.skybound.nl/articles/delphi-singleton/

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Graeme Geldenhuys
to Dean Zobec: You are right, beware of singletons. Being a simple pattern to implement it's often…
Dean Zobec wrote 15 lines
> >> Try this. > >> http://bdn.borland.com/article/22576 > > NewInstance/FreeInstance is what I would have recommended as well. > > > Maybe we should include an implementation in FPC by default ? > > How ? The article works as-is AFAIK. > > Btw, I think singletons are nonsense too. Why is a global variable evil, > and a singleton class not ? You are right, beware of singletons. Being a simple pattern to implement it's often misused and sometimes creates more problems than it solves, it's a global variable after all, and you should put an extra effort to try to avoid it as you would avoid a global variable.

I use singletons in the following cases.

gINI - Able to read/write to a application .INI file for storing a Form's state, position and size. It also stores specific user settings in there. The whole application accesses the same .INI file and each form doesn't even know the INI filename, they just use the methods of gINI.

gLog - Also part of tiOPF. Used for debugging purposes. Can log to File, GUI Window, Console or any mix of the lot. All controlled via command line parameters.

g<ApplicationName> - A container for a application, which contains list objects, currently selected user, etc. eg: gM2Application will contain the following typical properties: a LanguageList, CentreList, CurrentUser, CurrentCentre, SystemParameters, etc. It's a class encapsulating a application and acts as a container for often used objects in my application.

For unit testing, I can for example test the LanguageList without it being inside the gM2Application object. It can be used stand-alone. Things I have to test as part of gM2Application is the reference object like CurrentUser and CurrentCentre. I created a method called ClearDownData specifically for unit testing, which clears all data stored in a g<ApplicationName> object, so each unit test starts with a fresh copy, even though it is a Singleton.

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Matt Emson
to Graeme Geldenhuys
I use singletons in the following cases.

The problem with using singletons in this way is that they're not [very] thread safe. You end up needing a locking mechanism that gets tiring very quickly. I can't offer you a better solution, but I have worked on a project where it was a real problem, and so speak from experience. If you go down this route, you kind of force single threadedness on to your application - which obviously might be what you desire. Retro fitting threading semantics on to such an app is a complete nightmare though.

M

Graeme Geldenhuys
to Matt Emson
Matt Emson wrote
The problem with using singletons in this way is that they're not [very] thread safe. You end up needing a locking mechanism that gets tiring very

gINI and gLog are thread safe and well tested. Both use a caching system that buffers the entries in memory and writes out the data when the system is idle or the applications quits. This is very important for the gLog. The reason being, logging Visitor activity creates huge log files and would normally slow the system down if the caching system was not used.

Graeme Geldenhuys There's no place like S34° 03.168' E018° 49.342'
Matt Emson
to Graeme Geldenhuys
gINI and gLog are thread safe and well tested.

Out of interest, which type of locking mechanism do you use? I always favour the "CanLock", "IsLocked", "Unclock" style mechanism ala:

 if not (res.Lock) then
begin
   ; //recover
end
else
try
  ; //do work
finally
  res.Unlock;
end;

But I do find it tiresom, so any alternatives that do not revolve around "Critical Sections" (ala Windows) are always interesting to me. A lot of the code I write can't block, so this type of mechanism needs to be employed.

Marc Santhoff
to Graeme Geldenhuys: This is kinda what I have been using all along, except, I have a function, that creates…
Graeme Geldenhuys wrote 11 lines
On 12/8/06, Marc Santhoff wrote: > One working solution is to use a global var. This is bad but acceptable > for a singleton imo. If would be nice if the variable could be hidden. This is kinda what I have been using all along, except, I have a function, that creates the instance when used for the first time. I call it the Lazy mans Singleton. It works perfectly, if the developer knows about the global function! Otherwise, they might still try and create a instance of the class, which is what I am trying to prevent.

(Coming back on this topic late, sorry)

I've tried preventing a second instance like in the sources below, and it does work.

Besides that I'd like to know if it has some effect on allocated ressources behind the scenes in the constructor, will it allocate ressources never freed?

<snip>
unit singleton;
interface
{$mode objfpc}
type
  tsingleton = class
  	name: String;
  	constructor create;
  end;
implementation
var
  s: TSingleton;
constructor TSingleton.create;
begin
        if not(assigned(s)) then
        begin
                inherited;
                (*... do initializations ...*)
                s := self;
                writeln('creating new singleton');
        end else begin
        	self := s; // <-- Danger, Will Robinson!
        end;
end;
initialization
        s := NIL;
end.
end.
</snip>
<snap>
program singleton_test;
{$mode objfpc}
uses singleton;
var
	s, s2: TSingleton;
BEGIN
	s := TSingleton.create;
	s.name := 'one';
	writeln('name of s: '+s.name);
	s2 := TSingleton.create;
	s2.name := 'two';
	writeln('name of s: '+s.name);
	writeln('name of s2: '+s2.name);
END.
</snap>

Output:

$ ./singleton_test
creating new singleton
name of s: one
name of s: two
name of s2: two

If there are no drawbacks, this is a somewhat clean approach for single threaded or low threadcount applications (which is what I use, each application in question has it's own set of singletons)...

Marc

Steve Williams
to Marc Santhoff
Marc Santhoff wrote 13 lines
constructor TSingleton.create; begin if not(assigned(s)) then begin inherited; (*... do initializations ...*) s := self; writeln('creating new singleton'); end else begin self := s; // <-- Danger, Will Robinson! end; end;

This is where you lose memory. TObject.NewInstance is implicitly called before the constructor. It allocates memory for the instance. Now you have lost track of that memory by overwriting Self. Every time you call TSingleton.Create, you lose memory. Override NewInstance as shown in the link I listed previously in this thread for a solution that will not lose memory.

Sly This message and its attachments may contain legally privileged or confidential information. This message is intended for the use of the individual or entity to which it is addressed. If you are not the addressee indicated in this message, or the employee or agent responsible for delivering the message to the intended recipient, you may not copy or deliver this message or its attachments to anyone. Rather, you should permanently delete this message and its attachments and kindly notify the sender by reply e-mail. Any content of this message and its attachments, which does not relate to the official business of the sending company must be taken not to have been sent or endorsed by the sending company or any of its related entities. No warranty is made that the e-mail or attachment(s) are free from computer virus or other defect.
Marc Santhoff
to Steve Williams
Steve Williams wrote 19 lines
Marc Santhoff wrote: > constructor TSingleton.create; > begin > if not(assigned(s)) then > begin > inherited; > (*... do initializations ...*) > s := self; > writeln('creating new singleton'); > end else begin > self := s; // <-- Danger, Will Robinson! > end; > end; > This is where you lose memory. TObject.NewInstance is implicitly called before the constructor. It allocates memory for the instance. Now you have lost track of that memory by overwriting Self. Every time you call TSingleton.Create, you lose memory.

Yes, that's what I feared.

Override NewInstance as shown in the link I listed previously in this thread for a solution that will not lose memory.

Now I see, I should have read it earlier but missed it not following the complete thread.

Thanks,
Marc