I'm attempting to translate a small library that was written by a coworker in C# into Delphi. It relies heavily on generics and anonymous methods.

I'm attempting to translate a small library that was written by a coworker in C# into Delphi. It relies heavily on generics and anonymous methods.

I'm having issues attempting to pass an anonymous function as an argument to a procedure. I have code that looks like:

procedure TSomeObject.SomeProc(callback: TFunc);

The code that calls this procedure looks like:

someObject.SomeProc(
  function(in: string):Integer
  begin
    if Assigned(in) then
      Result := 1;
  end);

But the compiler just gives me:
 E2010 Incompatible types: 'System.SysUtils.TFunc>' and 'Procedure'

I've tried adding explicit type parameters. I've tried making the anonymous method an ordinary method and a stand alone function. Still get the same error message just a different type for the second operand. When I made it an object method it said the second type was 'Procedure of object' instead.

Anyone have a clue what I'm doing wrong?

Comments

  1. is there a parameter prefix in the declaration of TFunc?
    i.e.
    type
      TFunc = reference to function(const aValue:T1):T2;

    if so, 

    someObject.SomeProc(
      function(const in: string):Integer
      begin
        if Assigned(in) then
          Result := 1;
      end);

    ReplyDelete
  2. It's the TFunc defined in SysUtils:

    TFunc = reference to function (Arg1: T): TResult;

    I don't see anything out of the ordinary. Do you?

    ReplyDelete
  3. Also - Assigned on a string is a bit unusual - at least for me ;)

    ReplyDelete
  4. I just added that to fill space. I probably should have just wrote:

    //Do Something

    in the function body.

    ReplyDelete
  5. Wait a sec.

    procedure TSomeObject.SomeProc(callback: TFunc);

    Are T1 and T2 part of the TSomeObject? 
    i.e. TSomeObject ?

    If not, your call needs to be
    someObject.SomeProc(
      function(const in: string):Integer
      begin
        if Assigned(in) then
          Result := 1;
      end);

    ReplyDelete
  6. Lars Fosdal
    Well Delphi's type inference should make that unnecessary but as I said in the OP I've already tried adding explicit type parameters. No dice.

    ReplyDelete
  7. // Compiles and runs in XE 7.1
    program GenericsTypeInference;

    {$APPTYPE CONSOLE}

    {$R *.res}

    uses
      System.SysUtils;

    type
      TSomeObject = class
        procedure SomeProc(callback: TFunc);
      end;

    { TSomeObject }

    procedure TSomeObject.SomeProc(callback: TFunc);
    begin
    //  Do something
    end;

    var
      SomeObject : TSomeObject;
    begin
      try
        SomeObject := TSomeObject.Create;
        try

          SomeObject.SomeProc< String, Integer >(function(arg: string):Integer
            begin
              Result := 0;
            end);

        finally
          SomeObject.Free;
        end;

      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.

    ReplyDelete
  8. SomeObject.SomeProc(function(arg: string):Integer
            begin
              Result := 0;
            end);

    fails.

    ReplyDelete
  9. Type inference only works directly on arguments of the generic type. It does not look into compound types.

    ReplyDelete
  10. Ok. Didn't realize type inference was so limited in Delphi. The example I posted was simplified a little too much. The production code had much more complicated type parameters. Like:
    >>

    When inference didn't work I accidently transposed one of the type parameters when I attempted to fill them in at the call site.

    The error message identifying the right operand as simply 'procedure' is pretty useless for troubleshooting. If it had been expanded the way the left one was I probably would have noticed the problem sooner.

    ReplyDelete

Post a Comment