As promised in the previous post “Delphi: Default parameterless constructor” I will now try to create a new generic class that accepts a type parameter that has a “constructor” restriction (must have a default public parameterless constructor).
Let’s start off with a simple example:
type TMyClass = class end; TMyGenericClass<T: constructor> = class end; var GenObj: TMyGenericClass<TMyClass>; begin end.
This is a legitimate example that will compile. TMyClass inherits the default parameterless constructor from TObject. Even though this is not the result that you would expect in other languages, it’s still somehow correct.
Moving further, let’s check what happens if we declare a private default constructor:
type TMyClass = class private constructor Create(); end; TMyGenericClass<T: constructor> = class end; { TMyClass } constructor TMyClass.Create(); begin WriteLn('TMyClass.Create()'); end; var GenObj: TMyGenericClass<TMyClass>; begin end.
And here we will get a compile error. The requirement that TMyClass has a public parameterless constructor is not satisfied!
But don’t be too happy just yet! The next example cracks it again:
type TMyClass = class public constructor Create(const AParam: String); end; TMyGenericClass<T: constructor> = class end; { TMyClass } constructor TMyClass.Create(const AParam: String); begin WriteLn('TMyClass.Create()'); end; var GenObj: TMyGenericClass<TMyClass>; begin end.
It seems that the default constructor is yet again found — the one inherited from TObject.
The last one (I promise!) follows:
type TMyClass = class private constructor Create(); overload; public constructor Create(const AParam: String); overload; end; TMyGenericClass<T: constructor> = class end; { TMyClass } constructor TMyClass.Create(const AParam: String); begin WriteLn('TMyClass.Create()'); end; constructor TMyClass.Create; begin end; var GenObj: TMyGenericClass<TMyClass>; begin end.
Again, a compilation error is risen. We’re back on the right track.
The final conclusion to this post and the previous one is:
If you do not have/need a default public parameterless constructor in your class, you must still define a private one that would raise an Exception telling the programmer to not call it. Doing this you will ensure that your constructor is being executed and not the TObject provided one, resulting in a predictable object state. Also this will ensure that the “constructor” restriction will be enforced correctly!
~Yes, I know, Delphi sucks sometimes 🙂