Why can't I assign interface methods to function references?

Why can't I assign interface methods to function references?

type
  ISomeInterface = interface
    procedure PlainProc;
  end;

var
  myInterface: ISomeInterface;
  p: TProc;
begin
  p := myInterface.PlainProc; // nope
end.

Clearly I don't know how anonymous functions are implemented in sufficient detail :(

Comments

  1. Asbjørn Heid Anonymous methods are actually classes with one method called "Invoke" (excluding all the usual interface methods)

    ReplyDelete
  2. Nicholas Ring Thanks, I knew that part, but as far as I can tell, that doesn't really answer my question :(

    Perhaps I'm just being unusually dense this morning.

    ReplyDelete
  3. What I mean is, I know that if I had myObj instead, the variable would be captured (assuming it's not a global variable), ie stored in the hidden object implementing the anonymous function. What I don't get is why it can't capture an interface instance.

    ReplyDelete
  4. It's a limitation in the compiler as I reported 2 years ago already (http://qc.embarcadero.com/wc/qcmain.aspx?d=110364). Just with any other  method assigned to a method reference it should generate code that equals to this:

    var
      myInterface: ISomeInterface;
      p: TProc;
    begin
      p := procedure begin myInterface.PlainProc; end;
    end.

    ReplyDelete
  5. Stefan Glienke Thanks. And just as I thought XE7 had fixed all compiler related issues I had.

    ReplyDelete
  6. Asbjørn Heid *mad laughing* Dream on ;p

    ReplyDelete
  7. Stefan Glienke you made my day (:
    [hysterical laughter]

    ReplyDelete
  8. You can always use the hacking way!
    //------------------------------------------------------------------
    type
      ISomeInterface = interface
        procedure PlainProc;
      end;

      TSomeObject = class(TInterfacedObject, ISomeInterface)
        procedure PlainProc;
      end;

      TProcedure = procedure;

    function GetInterfaceMethodPtr(const PInterface; MethodIndex: Integer): PByte;
    var
      Pvt: PPointer;
      P: PPointer;
    begin
      Pvt := PPointer(PInterface)^; // Virtual Table !
      P := Pvt;
      Inc(P, MethodIndex);
      P := PPointer(P)^;
      Result := PByte(P);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Q: PByte;
      Proc: TProcedure absolute Q;
      myInterface: ISomeInterface;
      refProc: TProc;
    begin
      myInterface := TSomeObject.Create;
      Q := GetInterfaceMethodPtr(myInterface, 3); // myInterface.PlainProc;
      refProc := Proc;
      refProc();
    end;

    { TSomeObject }
    procedure TSomeObject.PlainProc;
    begin
      ShowMessage('Some Msg');
    end;
    //----------------------------------------------------------------
    Have a nice day.

    ReplyDelete
  9. Mahdi Safsafi omg, first this is a completely unnecessary hack for something that can be solved like I wrote above and second it will only work with the first method in an interface because the hidden Invoke method of an anonymous method is always the one with Index 3. You cannot simply redirect that to another index by casting around the vmt pointer without some stubbing code.

    ReplyDelete
  10. Stefan Glienke Sorry , i had not read the answer that you had suggested.

    ReplyDelete

Post a Comment