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 :(
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 :(
Asbjørn Heid Anonymous methods are actually classes with one method called "Invoke" (excluding all the usual interface methods)
ReplyDeleteAsbjørn Heid Here is some information about anonymous method implementation - http://chuacw.ath.cx/blogs/chuacw/archive/2012/01/02/secrets-of-the-implementation-of-the-delphi-anonymous-method.aspx
ReplyDeleteNicholas Ring Thanks, I knew that part, but as far as I can tell, that doesn't really answer my question :(
ReplyDeletePerhaps I'm just being unusually dense this morning.
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.
ReplyDeleteIt'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:
ReplyDeletevar
myInterface: ISomeInterface;
p: TProc;
begin
p := procedure begin myInterface.PlainProc; end;
end.
Stefan Glienke Thanks. And just as I thought XE7 had fixed all compiler related issues I had.
ReplyDeleteAsbjørn Heid *mad laughing* Dream on ;p
ReplyDeleteStefan Glienke you made my day (:
ReplyDelete[hysterical laughter]
You can always use the hacking way!
ReplyDelete//------------------------------------------------------------------
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.
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.
ReplyDeleteStefan Glienke Sorry , i had not read the answer that you had suggested.
ReplyDelete