Interface delegation (aka property implements keyword)

Interface delegation (aka property implements keyword)

Why the following snippet fails to compile with a "[dcc32 Error] Project1.dpr(21): E2291 Missing implementation of interface method IFoo.Foo"

Problem is around IFooEx augmenting IFoo, if I take that away it compiles fine

IFoo = interface
['{304DE439-B817-451C-AED3-40EDD1287B5C}']
procedure Foo;
end;

IFooEx = interface(IFoo)
['{DE4F1005-56DB-4031-A607-6728F1804F26}']
procedure FooEx;
end;

TFoo = class(TInterfacedObject, IFoo, IFooEx)
strict private
FFooImpl: IFoo;
strict protected
procedure FooEx;
property FooImpl: IFoo read FFooImpl implements IFoo;
public
constructor Create(const Foo: IFoo);
end;

Comments

  1. My workaround is hold my nose and write FooImpl.Whatever for every method..

    ReplyDelete
  2. FWIW TFoo.Create gets an IFoo as a parameter. I hope it's not about to be stored in FFooImpl. Delegated interface implementations should derive from TAggregatedObject. An instance of TAggregatedObject needs a reference back to its controller. In your case that would be an instance of TFoo. Otherwise you can get into trouble with memory leaks and unexpected behaviour when you cast from one interface type to another.

    ReplyDelete
  3. Christopher Wosinski you're absolutely right, but that's not really my problem

    ReplyDelete
  4. The point is that you don't implement IFooEx.Foo. Even though you delegate the implementation of IFoo via the implements it is missing the implementation of the Foo method that comes with IFooEx. The compiler message is a bit misleading because it says IFoo.Foo but technically it's IFooEx.Foo ("inherited" from IFoo)

    Although it looks like inheritance IFooEx does not really inherit from IFoo in regard to the Foo method - it can be completely different when implementing both interfaces in a class.

    In your example the interface delegation clause is not any helpful and adding a Foo method that just calls FFooImpl.Foo would be enough to satisfy the compiler (I guess the real code has a few more methods so the interface delegation clause there might be less code if it worked).

    ReplyDelete
  5. Stefan Glienke I know it happens because of interface "inheritance" (I prefer to call it "augment" or "enhance"). I just don't understand why the compiler cannot figure out that he can resolve the calls with the things it has at hand.

    Of course the whole point is: I'm very lazy and don't want to write FFooImpl.Whatever for every method

    ReplyDelete
  6. Agustin Ortu You can do this by splitting up the implementation:

    type
      TFooBase = class(TInterfacedObject, IFoo)
      strict private
        FFooImpl: IFoo;
      strict protected
        property FooImpl: IFoo read FFooImpl implements IFoo;
      public
        constructor Create(const Foo: IFoo);
      end;

      TFooEx = class(TFooBase, IFooEx)
      strict protected
        procedure FooEx;
      public
        constructor Create(const Foo: IFoo);
      end;

    { TFooBase }

    constructor TFooBase.Create(const Foo: IFoo);
    begin

    end;

    { TFooEx }

    constructor TFooEx.Create(const Foo: IFoo);
    begin
      inherited Create(Foo);
    end;

    procedure TFooEx.FooEx;
    begin

    end;

    var
      f: IFoo;
    begin
      f := TFooEx.Create(nil);
    end.

    ReplyDelete
  7. Asbjørn Heid true, but sometimes class inheritance becomes a constraint 😊

    ReplyDelete
  8. Agustin Ortu You mean that your TFooEx implementation already descends from something else and not TInterfacedObject?

    ReplyDelete
  9. Yep. Anyway the real point is me being very lazy and wanting the compiler to do boring job for me. I'm sticking with the approach suggested by Stefan Glienke​ and writing delegated calls my self. Introducing a parent class like you said works but I feel the code more complex

    ReplyDelete

Post a Comment