Class Implementing Two Interfaces with Duplicate Method Names

by Nov 27, 2019

Delphi only supports single inheritance. A Delphi class can only descend from a single parent class, but a Delphi class can implement multiple interfaces.

type
  TAthlete = class(THuman, IWalker, IJumper)

The TAthlete descends from the THuman parent class (which presumably descends from TInterfacedObject) and it implements both the IWalker and IJumper interfaces. What if both IWalker and IJumper contain a run method.

type
  THuman = class(TInterfacedObject)
    procedure walk; virtualend= Interface(IInterface)
    procedure run;
  end= Interface(IInterface)
    procedure run;
  endclass(THuman, IWalker, IJumper)
  end

Data Model

Right now TAthlete doesn't implement the members of IWalker or IJumper.

  • [dcc32 Error] E2291 Missing implementation of interface method IJumper.run
  • [dcc32 Error] E2291 Missing implementation of interface method IWalker.run

When we implement these interfaces in TAthlete, what if we want to have a different run method for IWalker vs IJumper? Enter the Method Resolution Clause.

Interface Method Resolution Clause

When a class implements two or more interfaces that have identically named methods, use method resolution clauses to resolve the naming conflicts. You can override the default name-based mappings by including method resolution clauses in a class declaration. We might implement those interfaces like this:

type
  TAthlete = class(THuman, IWalker, IJumper)
  public
    procedure IWalker.run = PowerWalk;
    procedure IJumper.run = RealRun;
  private
    procedure PowerWalk;
    procedure RealRun;
  end 

But what happens if I call Run on a class reference to an TAthlete object? It doesn't exist. There is no Run method on TAthlete, and both PowerWalk and RealRun are private, so they aren't accessible via a class reference either.

  var Athlete := TAthlete.Create;
  try
    (* These give E2003 Undeclared identifier
    Athlete.run;        // There is no Run method on TAthlete
    Athlete.PowerWalk;  // PowerWalk is Private
    Athlete.RealRun;    // Also private *)

    // To access Run we must have an Interface reference
    IWalker(Athlete).Run; // Calls TAthlete's RealRun method
    IJumper(Athlete).Run; // Calls TAthlete's PowerWalk method
  finally
    Athlete.Free;
  end

If we wanted to call Run on TAthlete we could do that with a little change.

type
  TAthlete = class(THuman, IWalker, IJumper)
  public
    procedure IWalker.Run = PowerWalk;
    procedure Run;
  private
    procedure PowerWalk;
  end

Now IJumper uses the default name-based mapping, which IWalker uses the manually mapped method

  var Athlete := TAthlete.Create;
  try
    Athlete.Run;          // We now have a Run method
    IWalker(Athlete).Run; // Calls TAthlete's PowerWalk method (not a real run)
    IJumper(Athlete).Run; // Calls the real Run method on TAthlete
  finally
    Athlete.Free;
  end

It seems like it would usually be a good idea to be explicit in all the methods implemented by interfaces when you have a conflict like this, but there could be a reason to be less explicit in certain use cases. It is great that Delphi gives you the flexibility to implement this either way necessary.