开发者

Would templates (or other technology) support the following construct?

开发者 https://www.devze.com 2023-01-21 10:54 出处:网络
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 befor

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

0

精彩评论

暂无评论...
验证码 换一张
取 消