Class constructor not called when class registration is done in that class constructor - delphi

I am writing a simple dependency injection / inversion of control system based on a TDictionary holding abstract class references with their respective implementor classes.
My goals are:
Avoid direct instantiation by type (obviously).
Inclusion of a class' unit in the dpr should be enough to have it registered and be available for selection and instantiation through the di/ioc system.
Declare concrete implementing classes in implementation section only.
Use class constructors instead of initialization sections.
Btw, I am aware that using class constructors to take advantage of smart linking and wanting the inclusion of a unit to be enough to make a class available are defeating each other. I want to use class constructors instead of initialization sections for other reasons as well. And I would like to keep all class initialization/registration code together instead of having to split it between the class constructor and initialization section.
Problem
I want the registration of the class into the factory to be in the class constructor. Unfortunately, the compiler doesn't think the class is "touched" by just using its type in its own class constructor.
When I put the registration function in the initialization section, then the compiler does think the class is touched and calls the class constructor. But that defeats the object of my exercise of keeping all class initialization code in the class constructor.
Two questions
Should the compiler consider the use of the class in its own class constructor "touching the class" or is that too much to expect the compiler to do?
Does anybody have any clever ideas on how I can still achieve my goals without using the initialization section?
Example
The abstract classes used in the application:
TSite = class abstract (TObject)
function GetURL: string; virtual; abstract;
property URL: string read GetURL;
end;
TSites = class (TList<TSite>);
TThisApplication = class abstract (TObject)
function Sites: TSites; virtual; abstract;
end;
The concrete implementing class (declared in the implementation section!) for TThisApplication
TThisApplicationConcrete = class(TThisApplication)
class constructor ClassCreate;
strict private
FSites: TSites;
function Sites: TSites; override;
end;
class constructor TThisApplicationConcrete.ClassCreate;
begin
RegisterImplementorClass(TThisApplication, TThisApplicationConcrete);
end;
function TThisApplicationConcrete.Sites: TSites;
var
SiteList: TSites;
begin
if not Assigned(FSites) then begin
SiteList := TSites.Create; // Change to use factory
//RetrieveSites(SiteList);
FSites := SiteList;
end;
Result := FSites;
end;
The function to get an instance of TThisApplication:
function ThisApplication: TThisApplication;
var
ImplementorClass: TClass;
begin
ImplementorClass := GetImplementorClass(TThisApplication);
if Assigned(ImplementorClass) then begin
Result := ImplementorClass.Create as TThisApplication;
end else begin
Result := nil;
end;
end;
This is currently coded in a separate function, but it w/could be moved to the factory.
Full example code
If anybody would like to experiment, I have the full code of my test projects available at : http://www.bjsoftware.com/delphistuff/stackoverdlow/classconstructors.zip
Zip contents:
4 projects all using the same source files, differing only in conditional defines (that's why the dproj's are also included)
4 source files
groupproj and its dsk with all 4 projects
RunTestApps.cmd to run all 4 projects
Results.txt with the output of my run of the RunTestApps.cmd
WriteUp.txt with the text of this question
Please bear in mind that at all times you need to do a "Build All Projecs" because all dcu's and exe's are going to the source dir and otherwise you are going to face a lot of errors and/or confusion because the exe isn't doing what its name indicates.

This is as expected. As Uwe pointed out, a self-referential class constructor isn't enough to trigger inclusion. Placing the reference in the initialization section will do the trick since that is outside the class itself. Trying to self-reference a class for inclusion is akin to trying pull yourself out of a deep hole by pulling on your own suspenders.

As long as you don't use the class anywhere outside the class itself, the compiler takes this as the class not used at all and hence won't call the class constructor. So I guess you have to use the intialization section instead of tweaking the code to fool the compiler. Take the pragmatic approach instead of the dogmatic one. It will be more readable anyway.

I think you expect the class constructor to work differently than it has been designed to. Class constructor don't get called "just before" the first create. (Not in WIN32 delphi at least). If a class is referenced, its class constructor will run before the unit's initialization code.
If the only reference that you have to your class happens to be inside said class, then no code actually linked into your application refer to said class. Therefore, its class constructor will never get called.
I believe register functions belongs to the initialization section. Having the register function there will force the class constructor to also be executed. I don't see why you would want/require the register code to be placed into the class constructor.
If you want more information about the way class constructor/destructor works, you can read this pretty good article by Allen Bauer:
http://blogs.embarcadero.com/abauer/2009/09/04/38899

Related

override, virtual/dynamic in Delphi constructors

The one with virtual/dynamic
// declare in Child Class
constructor Create; virtual;
constructor TChildClass.Create;
begin
inherited;
end;
The one with override.
// declare in Child Class
constructor Create; override;
constructor TChildClass.Create;
begin
inherited;
end;
The one with nothing
// declare in Child Class
constructor Create;
constructor TChildClass.Create;
begin
inherited;
end;
Are these the same thing? It looks confusing.
Yes, there is a difference, but let's deal with the virtual keyword in more basic OOP terms first, yet still how it applies to Delphi methods.
When you declare a derived (child) class, and implement a method as "override", it means that you're overriding (surprise) the matching method of the base class.
This means that you can write code like this:
var child : TBaseClass;
begin
child := TChildClass.Create; // note that it is stored in TBaseClass variable
child.VirtualMethodDefinedInBaseClassThatHasBeenOverriddenInChildClass;
This will call the method in the child class, even if the variable is defined to be of the base class type. This is the whole purpose of virtual methods, you can access the object through a reference of a more general type, and still call methods that have been written for the particular type of object you're dealing with.
If you have a virtual method in the base class that you chose not to override in the child class, but instead reintroduce, you're effectively replacing it in some cases. Note that in most cases you need to tell the compiler that you really meant to do this, though I'm unsure about what Delphi requires here.
Basically, if your variable is of type TBaseClass, and you call a virtual method on it, that has been reintroduced in the TChildClass, it will still call the method in the base class.
However, if your variable is of type TChildClass, and you call that method on it, you will get the new method instead.
Now, for constructors, in Delphi, it is slightly different.
The point of virtual constructors is to be able to virtually construct objects, and to do that, Delphi also has "class types".
You can say this:
type TClassToUse = class of TBaseClass;
var cls : TClassToUse;
obj : TBaseClass;
begin
cls := TChildClass;
obj := cls.Create;
(note that my Delphi knowledge is a bit rusty here, if anyone spots bugs or glaring problems in the above code, please let me know or just fix it)
Here we store a "class" in a variable, and then ask the class to please construct an object for us. This allows us to switch out which class to create, but we also need to declare the constructors we want to use virtual, otherwise we will have problems.
So in the above code, if you declared the constructor as virtual in TBaseClass, and then override it in TChildClass (which the code is actually using in cls), the overridden constructor is the one that will be used.
If, on the other hand, you don't declare the constructor as virtual, we're back to the base class constructor. Virtual basically means to figure out the right method to execute at runtime, whereas non-virtual will figure it out at compile time.
Reintroduction as described for normal methods above, also works this way.
However, virtual constructors are only used as virtual when used through a class type.
No, static and virtual methods are not the same thing.
And override is a case of virtual method.
http://en.wikipedia.org/wiki/Virtual_function
http://docwiki.embarcadero.com/RADStudio/XE4/en/Methods#Method_Binding
Constructors bring nothing special here - they conform to the same rules as other methods for the question

How do I mock a class that doesn't have virtual methods?

Let's assume you have a very well designed Delphi project, which respects the dependency injection and some other good practices.
Now let's assume you need to mock a class defined as:
TMyClass = class
public
procedure Method1;
procedure Method2
end;
Method1 and Method2 are not virtual. What do you do in this case? To mock an object we need to inherit it and override every method you want to mock, but it is not possible in this case because they are not virtual. Should I change the source code to add virtual on every method I need to mock? Is not it bad?
Edit
I was thinking about creating a compiler directive to make all fields in the class to be virtual, is it a good ideia? Only my test suite is going to set the compiler directive.
EDIT2*
Embarcadero should provide an easy way of changing a method pointer of a class to another method point, without the need for virtual.
Make the methods virtual so you can mock them. (They don't need to be abstract.)
If you cannot do that, then wrap the class with another class. Make the wrapper's methods virtual, and in the default implementation, just forward call calls to the original class. Wherever your program uses the original class, replace it with the wrapper. Now, mock the wrapper.
To mock an object we need to inherit
it, but it is not possible in this
case.
I'd recommend that every class that you say "I need to mock this" should end up being based on an interface.
In other words, if you have methods that need to be mocked, they should be put into an interface, and then the class to be mocked implements that interface. Then, you create the mock by implementing the same interface in the mock object.
The alternative is to use a Mocking library. You can look at these SO question:
What is your favorite Delphi mocking library?
and this framework includes mocking objects as well:
http://code.google.com/p/emballo/
Mocking objects should also encourage the proper use of dependency injection in your code.
You should not only make the methods virtual, you should declare a pure virtual base class, and make the other classes use only the pure virtual base class name. Now you can use what we call the "Liskov substitution principle", and you can make as many concrete subtypes of the abstract base class as you need. Since the abstract base class works just like an Interface works in delphi, minus the reference counting part, you get the best of both worlds. You can really keep your app code simple, and reduce bad coupling this way, plus you get unit testable "composite objects" that you put together yourself.
// in UnitBase.pas
TMyClassBase = class
public
procedure Method1; virtual; abstract;
procedure Method2; virtual; abstract;
end;
// in UnitReal.pas
TMyClassReal = class(TMyClassbase)
public
procedure Method1; override;
procedure Method2; override;
end;
// in UnitMock.pas
TMyClassMock = class(TMyClassbase)
public
procedure Method1; override;
procedure Method2; override;
end;
In the place that uses "TMyClass", change it to use TMyClassbase:
TMyOtherClass = class(TMyOtherClassBase)
private
FMyThing:TMyClassbase;
public
property MyThing:TMyClassBase read FMyThing write FMyThing;
end;
By connecting TMyOtherclass at runtime you can decide whether to use the real or mock class:
// in my realapp.pas
MyOtherClassObj := TMyotherClass.Create;
MyOtherClassObj.MyThing := TMyOtherClassReal.Create; // real object
// in my unittest.pas
MyOtherClassObj := TMyotherClass.Create;
MyOtherClassObj.MyThing := TMyOtherClassMock.Create; // mock object
(Don't forget to make a way to free MyOtherClassObj.MyThing later, or you'll have a leak)

Delphi class references... aka metaclasses... when to use them

I've read the official documentation and I understand what class references are but I fail to see when and why they are best solution compared to alternatives.
The example cited in the documentation is TCollection which can be instantiated with any descendant of TCollectionItem. The justification for using a class reference is that it allows you to invoke class methods whose type is unknown at compile time (I assume this is the compile time of TCollection). I'm just not seeing how using TCollectionItemClass as an argument is superior to using TCollectionItem. TCollection would still be able to hold any descendant of TCollectionItem and still be able to invoke any method declared in TCollectionItem. Wouldn't it?
Compare this with a generic collection. TObjectList appears to offer much the same functionality as TCollection with the added benefit of type safety. You are freed from the requirement to inherit from TCollectionItem in order to store your object type and you can make a collection as type specific as you want. And if you need to access item's members from within the collection you can use generic constraints. Other than the fact that class references are available to programmers prior to Delphi 2009 is there any other compelling reason to use them over generic containers?
The other example given in the documentation is passing a class reference to a function that acts as an object factory. In this case a factory for creating objects of type TControl. Its not really apparent but I'm assuming the TControl factory is invoking the constructor of the descendant type passed to it rather than the constructor of TControl. If this is the case then I'm starting to see at least some reason for using class references.
So I guess what I'm really trying to understand is when and where class references are most appropriate and what do they buy a developer?
MetaClasses and "class procedures"
MetaClasses are all about "class procedures". Starting with a basic class:
type
TAlgorithm = class
public
class procedure DoSomething;virtual;
end;
Because DoSomething is a class procedure we can call it without an instance of TAlgorithm (it behaves like any other global procedure). We can do this:
TAlgorithm.DoSomething; // this is perfectly valid and doesn't require an instance of TAlgorithm
Once we've got this setup we might create some alternative algorithms, all sharing some bits and pieces of the base algorithm. Like this:
type
TAlgorithm = class
protected
class procedure DoSomethingThatAllDescendentsNeedToDo;
public
class procedure DoSomething;virtual;
end;
TAlgorithmA = class(TAlgorithm)
public
class procedure DoSomething;override;
end;
TAlgorithmB = class(TAlgorithm)
public
class procedure DoSomething;override;
end;
We've now got one base class and two descendent classes. The following code is perfectly valid because we declared the methods as "class" methods:
TAlgorithm.DoSomething;
TAlgorithmA.DoSomething;
TAlgorithmB.DoSomething;
Let's introduce the class of type:
type
TAlgorithmClass = class of TAlgorithm;
procedure Test;
var X:TAlgorithmClass; // This holds a reference to the CLASS, not a instance of the CLASS!
begin
X := TAlgorithm; // Valid because TAlgorithmClass is supposed to be a "class of TAlgorithm"
X := TAlgorithmA; // Also valid because TAlgorithmA is an TAlgorithm!
X := TAlgorithmB;
end;
TAlgorithmClass is a data type that can be used like any other data type, it can be stored in a variable, passed as a parameter to a function. In other words we can do this:
procedure CrunchSomeData(Algo:TAlgorithmClass);
begin
Algo.DoSomething;
end;
CrunchSomeData(TAlgorithmA);
In this example the procedure CrunchSomeData can use any variation of the algorithm as long as it's an descendant of TAlgorithm.
Here's an example of how this behavior may be used in a real-world application: Imagine a payroll-type application, where some numbers need to be calculated according to an algorithm that's defined by Law. It's conceivable this algorithm will change in time, because the Law is some times changed. Our application needs to calculate salaries for both the current year (using the up-to-date calculator) and for other years, using older versions of the algorithm. Here's how things might look like:
// Algorithm definition
TTaxDeductionCalculator = class
public
class function ComputeTaxDeduction(Something, SomeOtherThing, ThisOtherThing):Currency;virtual;
end;
// Algorithm "factory"
function GetTaxDeductionCalculator(Year:Integer):TTaxDeductionCalculator;
begin
case Year of
2001: Result := TTaxDeductionCalculator_2001;
2006: Result := TTaxDeductionCalculator_2006;
else Result := TTaxDeductionCalculator_2010;
end;
end;
// And we'd use it from some other complex algorithm
procedure Compute;
begin
Taxes := (NetSalary - GetTaxDeductionCalculator(Year).ComputeTaxDeduction(...)) * 0.16;
end;
Virtual Constructors
A Delphi Constructor works just like a "class function"; If we have a metaclass, and the metaclass knows about an virtual constructor, we're able to create instances of descendant types. This is used by TCollection's IDE Editor to create new items when you hit the "Add" button. All TCollection needs to get this working is a MetaClass for a TCollectionItem.
Yes a Collection would still be able to hold any descendant of TCollectionItem and to invoke methods on it. BUT, it wouldn't be able to instantiate a new instance of any descendant of a TCollectionItem. Calling TCollectionItem.Create constructs an instance of TCollectionItem, whereas
private
FItemClass: TCollectionItemClass;
...
function AddItem: TCollectionItem;
begin
Result := FItemClass.Create;
end;
would construct an instance of whatever class of TCollectionItem descendant is held in FItemClass.
I haven't done much with generic containers, but I think that given a choice, I would opt for the generic container. But in either case I'd still have to use a metaclass if I wanted to have the list instantiate and do whatever else needs to be done when an item is added in the container and I do not know the exact class beforehand.
For example an observable TObjectList descendant (or generic container) could have something like:
function AddItem(aClass: TItemClass): TItem;
begin
Result := Add(aClass.Create);
FObservers.Notify(Result, cnNew);
...
end;
I guess in short the advantage/benefit of metaclasses is any method/class having only knowledge of
type
TMyThing = class(TObject)
end;
TMyThingClass = class of TMyThing;
is able to construct instances of any descendant of TMyThing whereever they may have been declared.
Generics are very useful, and I agree that TObjectList<T> is (usually) more useful than TCollection. But class references are more useful for different scenarios. They're really part of a different paradigm. For example, class references can be useful when you have a virtual method that needs to be overridden. Virtual method overrides have to have the same signature as the original, so the Generics paradigm doesn't apply here.
One place where class references are used heavily is in form streaming. View a DFM as text sometime, and you'll see that every object is referred to by name and class. (And the name is optional, actually.) When the form reader reads the first line of an object definition, it gets the name of the class. It looks it up in a lookup table and retrieves a class reference, and uses that class reference to call that class's override of TComponent.Create(AOwner: TComponent) so it can instantiate the right kind of object, and then it starts applying the properties described in the DFM. This is the sort of thing that class references buy you, and it can't be done with generics.
I also would use a metaclass whenever I need to be able to make a factory that can construct not only one hard-coded class, but any class that inherits from my base class.
Metaclasses are not the term I am familiar with in Delphi circles however. I believe we call them class references, which has a less "magic" sounding name, so it's great that you put both common monikers in your question.
A concrete example of a place I have seen this used well is in the JVCL JvDocking components where a "docking style" component provides metaclass information to the base docking component set, so that when a user drags their mouse and docks a client form to the docking host form, the "tab host" and "conjoin host" forms that show grabber bars (similar in appearance to the title bar of a regular undocked window) can be of a user-defined plug-in class, that provides a customized appearance and customized runtime functionality, on a plug-in basis.
In some of my applications I have a mechanism that connects classes to forms capable of editing instances of one or more of that classes. I have a central list where those pairs are stored: a class refernce and a form class reference. Thus when I have an instance of a class I can lookup the corresponding form class, create a form from it and let it edit the instance.
Of course this could also be implemented by having a class method returning the appropriate form class, but that would require the form class to be known by the class. My approach makes a more modular system. The form must be aware of the class, but not the other way round. This can be a key point when you cannot change the classes.

Static classes in Delphi (Win32)

Is it in Delphi (Win32) possible to declare a whole class (not only a function of the class) as static?
Looks like user search for "class functions":
type
TSomeClass = class
class procedure MyFunction(...);
This is like static method, so, call it:
TSomeClass.MyFunction(...);
I assume you mean static classes like in .net (and not "static" as in traditional Delphi/Native) - and the answer to that is no.
I would use an abstract class (not to be confused with an abstract method in a class) to prevent it from being instantiated instead of demoting the constructor to protected:
TMyClass = class abstract
public
class procedure DoStuff; static;
end;
That will enforce the singleton pattern and prevent any instantiations period.
I am not quite sure what you mean by a "static class". You can declare a class, that has only class methods, so these methods can be called without instantiating the class.
TSomeClass.SomeMethod;
Is that what you want?
Not natively.
Depending on what you need it for, if for the purposes of your code, in some use cases you could replace it with a Singleton Pattern object.
For walkthrough on implementing this I'd recommend this guide which, covers almost any version of delphi, but if you're using Delphi 2010 you could also use the new class Constructors/Destructors for improved results.
You could create a class that contains nothing but static methods. If you have to maintain some sort of state, then the state variables should be passed as var parameters. There is no way to "properly" access static variables other than having a set of global variables in the implementation section of the class OUTSIDE the scope of the class, for example:
UNIT TestUnit;
INTERFACE
Type
TStaticClass = Class
public
procedure Foo(var Bar:String); static;
end;
IMPLEMENTATION
var
LastBar : String; // the last bar
LastRes : string; // the last result
Procedure TStaticClass.Foo(var Bar:String);
begin
if Bar <> LastBar then
LastRes := SomeCPUExpensiveProcess(Bar);
LastBar := Bar;
Bar := LastRes;
end;
INITIALIZATION
LastBar := '';
LastRes := SomeCPUExpensiveProcess('');
END.
You can also create a new unit called uDG_Utils for example, define a class, define a global variable for that class and in the initialization and finalization section you manage the class constructor and destructor.
Now all you need to do is call it like mySuperDuperClass.SuperMethod...
EDIT
I have edited this post to remove it. The answer is admittedly bad and deserves the down-votes. I don't want it to remain here to confuse or mislead anyone further.

Class Helper for generic class?

I'm using Delphi 2009. Is it possible to write a class helper for a generic class, i.e. for TQueue . The obvious
TQueueHelper <T> = class helper of TQueue <T>
...
end;
does not work, nor does
TQueueHelper = class helper of TQueue
...
end;
As documented in the Delphi help, class helpers are not designed for general purpose use and they are incorrectly perceived as having a number of limitations or even bugs as a result.
nevertheless there is a perception - incorrect and dangerous in my view - that these are a legitimate tool in the general purpose "toolkit". I have blogged about why this is wrong and subsequently about how you can go some way to mitigate the dangers by following a socially responsible coding pattern (although even this isn't bullet proof).
You can achieve much the effect of a class helper without any of these bugs or limitations or (most importantly) risks by using a hard cast to a "pseudo" class derived from the class you are trying to extend. i.e instead of:
TFooHelper = class helper for TFoo
procedure MyHelperMethod;
end;
use
TFooHelper = class(TFoo)
procedure MyHelperMethod;
end;
Just like with a "formal" helper, you never instantiate this TFooHelper class, you use it solely to mutate the TFoo class, except in this case you have to be explicit. In your code when you need to use some instance of a TFoo using your "helper" methods you then have to hard cast:
TFooHelper(someFoo).MyHelperMethod;
Downsides:
you have to stick to the same rules that apply to helpers - no member data etc (not really a downside at all, except that the compiler won't "remind you").
you have to explicitly cast to use your helper
If using a helper to expose protected members you have to declare the helper in the same unit that you use it (unless you expose a public method which exposes the required protected members)
Advantages:
Absolutely NO risk that your helper will break if you start using some other code that "helps" the same base class
The explicit typecasting makes it clear in your "consumer" code that you are working with the class in a way that is not directly supported by the class itself, rather than fudging and hiding that fact behind some syntactic sugar.
It's not as "clean" as a class helper, but in this case the "cleaner" approach is actually just sweeping the mess under the rug and if someone disturbs the rug you end up with a bigger mess than you started with.
I currently still use Delphi 2009 so I thought I'd add a few other ways to extend a generic class. These should work equally well in newer versions of Delphi. Let's see what it would look like to add a ToArray method to a List class.
Interceptor Classes
Interceptor classes are classes that are given the same name as the class they inherit from:
TList<T> = class(Generics.Collections.TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray;
end;
function TList<T>.ToArray: TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := Self[I];
end;
end;
Notice you need to use the fully qualified name, Generics.Collections.TList<T> as the ancestor. Otherwise you'll get E2086 Type '%s' is not completely defined.
The advantage of this technique is that your extensions are mostly transparent. You can use instances of the new TList anywhere the original was used.
There are two disadvantages to this technique:
It can cause confusion for other developers if they aren't aware that you've redefined a familiar class.
It can't be used on a sealed class.
The confusion can be mitigated by careful unit naming and avoiding use of the "original" class in the same place as your interceptor class. Sealed classes aren't much of a problem in the rtl/vcl classes supplied by Embarcadero. I only found two sealed classed in the entire source tree: TGCHandleList(only used in the now defunct Delphi.NET) and TCharacter. You may run into issues with third party libraries though.
The Decorator Pattern
The decorator pattern lets you extend a class dynamically by wrapping it with another class that inherits its public interface:
TArrayDecorator<T> = class abstract(TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray; virtual; abstract;
end;
TArrayList<T> = class(TArrayDecorator<T>)
private
FList: TList<T>;
public
constructor Create(List: TList<T>);
function ToArray: TListDecorator<T>.TDynArray; override;
end;
function TMyList<T>.ToArray: TListDecorator<T>.TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := FList[I];
end;
end;
Once again there are advantages and disadvantages.
Advantages
You can defer introducing the new functionally until its actually needed. Need to dump a list to an array? Construct a new TArrayList passing any TList or a descendant as a parameter in the constructor. When you're done just discard the TArrayList.
You can create additional decorators that add more functionality and combine decorators in different ways. You can even use it to simulate multiple inheritance, though interfaces are still easier.
Disadvantages
It's a little more complex to understand.
Applying multiple decorators to an object can result in verbose constructor chains.
As with interceptors you can't extend a sealed class.
Side Note
So it seems that if you want to make a class nearly impossible to extend make it a sealed generic class. Then class helpers can't touch it and it can't be inherited from. About the only option left is wrapping it.
As near as I can tell, there's no way to put a class helper on a generic class and have it compile. You ought to report that to QC as a bug.

Resources