Shouldn't the compiler be able to devirtualize the call in the interface trampoline methods it generates for IFoo?

Shouldn't the compiler be able to devirtualize the call in the interface trampoline methods it generates for IFoo? It knows that it can only point to TFoo.Test

See this code:

type
IFoo = interface
procedure Test;
end;

TAbstractFoo = class(TInterfacedObject)
procedure Test; virtual; abstract;
end;

TFoo = class(TAbstractFoo)
procedure Test; override;
end;

TSealedFoo = class sealed(TFoo, IFoo)
end;

procedure TFoo.Test;
begin
end;

var
foo: IFoo;
fooA: TAbstractFoo;
fooB: TFoo;
fooC: TSealedFoo;
begin
foo := TSealedFoo.Create;
foo.Test;

fooC := TSealedFoo.Create;
fooB := fooC;
fooA := fooC;
fooA.Test; // virtual call
fooB.Test; // virtual call
fooC.Test; // static call to TFoo.Test

When calling the interface method and inspecting the disassembly you can see that it does the virtual call in the compiler generated trampoline method (and on win32 also suffers from a defect described here: http://andy.jgknet.de/blog/2016/05/whats-wrong-with-virtual-methods-called-through-an-interface/)

I strongly believe that the compiler should devirtualize these calls when it is able to. Before anyone asks why would you do virtual methods behind interfaces: because sometimes you want to provide a base class that already implements the base behavior and you only need to override if you want specific behavior.

Especially since we don't have interface helpers / extension methods you might have a design where the interface offers a rich API which internally just redirects to other methods where maybe only one needs to be implemented. So you can make that method virtual abstract while all the other methods ultimately call this one - all already implemented in the base class.

Comments