Search code examples
delphigenericsanonymous-methods

What generic constraint do I use for an anonymous method type?


I would like to declare a generic record like so:

type
  TMyDelegate<T: constraint> = record
  private
    fDelegate: T;
  public
    class operator Implicit(a: T): TMyDelegate;
    class operator Implicit(A: TMyDelegate: T);
  end;

I'd like to limit T to reference to procedure/function. (As much as possible).

I've tried this, but it does not compile:

program Project3;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type

  TProc1 = reference to procedure(a: Integer);
  TProc2 = reference to procedure(b: TObject);

  TTest<T: TProc1, TProc2> = record
  private
    fData: T;
  public
    class operator Implicit(a: T): TTest<T>;
    class operator Implicit(a: TTest<T>): T;
  end;

  { TTest<T> }

class operator TTest<T>.Implicit(a: T): TTest<T>;
begin
  Result.fData:= a;
end;

class operator TTest<T>.Implicit(a: TTest<T>): T;
begin
  Result:= a.fData;
end;

var
  Delegate1: TProc1;
  Delegate2: TProc2;

var
  MyTest1: TTest<TProc1>;  <<-- error
  MyTest2: TTest<TProc2>;

begin
  MyTest1:=
    procedure(a: Integer)
    begin
      WriteLn(IntToStr(a));
    end;
end.

This gives compile error:

[dcc32 Error] Project3.dpr(39): E2514 Type parameter 'T' must support interface 'TProc2'

Is there a way to constrain a generic type to (a list of) anonymous types?


Solution

  • There is no way to specify such a constraint. Possible constraints are:

    • Value type.
    • Class, derived from specific ancestor.
    • Interface, derived from specific ancestor.
    • Parameterless constructor.

    This is covered in the documentation: http://docwiki.embarcadero.com/RADStudio/en/Constraints_in_Generics

    What the documentation does not make clear is that reference procedures types count as interfaces. Which is why your generic type compiles, with that constraint. But this is never any use to you. Because reference procedure types have no inheritance. And so the only thing that can meet a specific reference procedure type constraint is something of that specific type.

    In fact your type cannot be instantiated. That's because the constraint

    T: TProc1, TProc2
    

    specifies that T supports both of those reference procedure interfaces. And nothing can do that. Nothing can simultaneously support both TProc1 and TProc2.