Would templates (or other technology) support the following construct?
This is kind of a follow-up from my other question.
When I first heard about generics, it was before the release of Delphi 2009 (Where they introduced it first). I know it was supported in .Net before that, but I have yet to dig in that realm.
Reading about generics, I learned that it allowed class to have a variable argument to it, and that whatever value you passed to it would then be replaced through all the code of the class.
The way generics were described (or at least, what I understood generics allowed) was that, given the following declaration:
procedure TMyClass<T>.Init;
begin
FField := T.Create(nil);
end;
I assumed it would work. I assumed where the compile would fail is as follow:
begin
TMyClass<TComponent>.Create; //Works correctly
TMyClass<TObject>.Create; //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter
TMyClass<string>.Create; //Doesn't work, not an object.
end;
Now, I well know I开发者_StackOverflow was wrong. So, what I wonder now, is there a technology/language feature that would support such a construct. Code templates perhaps? Generics in other programming languages? Or maybe something else?
Now, I well know I was wrong. So, what I wonder now, is there a technology/language feature that would support such a construct. Code templates perhaps? Generics in other programming languages? Or maybe something else?
Generics in C# have the power that you want. Templates in C++ are even stronger - code generated via template is identical to code written by hand, except for the part where they can only be compiled inline, which sucks.
@Gamecat, you cannot have TObject
as a constraint, but you can have class
as a constraint (which nicelly covers that lack of TObject
constraint).
Note that no matter if you use TObject
or class
, you cannot call the Create
with a parameter without a trick.
Example 1: class
constraint:
unit Unit1;
interface
uses
Classes;
type
TMyClass<T: class, constructor> = class
strict private
FField: T;
public
procedure Init;
end;
implementation
procedure TMyClass<T>.Init;
begin
FField := T.Create();
end;
end.
Example 2: TComponent
as a constraint, and parameter in the Create
unit Unit2;
interface
uses
Classes;
type
TMyClass<T: TComponent, constructor> = class
strict private
FField: T;
public
procedure Init;
end;
implementation
procedure TMyClass<T>.Init;
var
ComponentClass: TComponentClass;
begin
ComponentClass := T;
FField := ComponentClass.Create(nil);
end;
end.
In addition to the class
constraint, you can also have a record constraint.
With that, you need the Default
to initialize fields:
unit Unit3;
interface
uses
Classes;
type
TMyClass<T: record> = class
strict private
FField: T;
public
procedure Init;
end;
implementation
procedure TMyClass<T>.Init;
begin
FField := Default(T);
end;
end.
Hope that sheds some light on generics and constraints.
--jeroen
You can put constraint(s) on a generic type. You need this if you want to use certain aspects of that type. For example a method.
If you want to call a constructor, you need to give the consructor constraint next to the class constraint:
type
TMyClass<T: TComponent, constructor> = class
// ..
end;
procedure TMyClass<T>.Init;
begin
FField := T.Create(nil);
end;
Unfortunately TObject isn't a valid constraint. (according to Delphi XE).
Now, I well know I was wrong. So, what I wonder now, is there a technology/language >feature that would support such a construct. Code templates perhaps? Generics in other >programming languages? Or maybe something else? This can be risky or even meaningless. If you call method X on the generic and you instantiate it with a class that doesn't support method X, what is the correct behaviour...
@Ken: In order for code like you requested to work in a real generic way, you would need to have a unified typing tystem that merges both reference types (classes) and value types (strings, integers, etc).
Historically, native Delphi doesn't have such a typing system (.NET has, and generics in Delphi Prism supports it, just as C# and VB.NET do).
Working around that is difficult; Allen Bauer gave it a shot implementing a Nullable type, and he had to do some serious twisting to implement only the Equals (=) and NotEquals (<>) operator behaviour in a way that covers both reference and value types.
So supporting these will be tough, but probably doable:
begin
TMyClass<TComponent>.Create; //Works correctly
TMyClass<TObject>.Create; //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter
TMyClass<string>.Create; //Doesn't work, not an object.
end;
--jeroen
精彩评论