Matt Allwood
Matt Allwood

Reputation: 1438

Method of parameterised Type must not use local symbol error when making generic interface factory

I am trying to write a basic factory method to return a generic interfaced class.

interface
type
  IGenInterface<T> = interface
    function TestGet:T;
  end;

  TBuilder<T> = class
    class function Build: IGenInterface<T>;
  end;

  TBuilder = class
    class function Build<T>: IGenInterface<T>;
  end;
implementation
type
  TInterfaceImpl<T> = class(TInterfacedObject, IGenInterface<T>)
    function TestGet:T;
  end;

{ TBuilder }

class function TBuilder.Build<T>: IGenInterface<T>;
begin
  result := TInterfaceImpl<T>.create;
end;

{ TInterfaceImpl<T> }

function TInterfaceImpl<T>.TestGet: T;
begin

end;

It looks simple enough, and I'm sure I've written similar code before, but as soon as I try to compile I get E2506: Method of parameterized type declared in interface section must not use local symbol '.TInterfaceImpl` 1'. Neither flavour of TBuilder work, both failing with the same error.

Now I'm not sure where the . and 1 are coming from. In my 'real' code, the . isn't there, but the ` 1 is.

I've had a look at the other two SO questions that reference this error, but I'm not using any constants or assigning variables (other than the function return) nor do I have any class vars.

Does anyone have a way to do this without having to move a lot of code into my interface?

Upvotes: 2

Views: 217

Answers (1)

David Heffernan
David Heffernan

Reputation: 612954

The issue relates to an implementation detail of generics. When you come to instantiate the generic type in a different unit it needs to see the TInterfaceImpl<T> type in that other unit. But the compiler cannot see it because it is in the implementation section of a different unit. So the compiler objects, as you have observed.

The simplest fix is to move TInterfaceImpl<T> to be a private type declared inside one of the types declared in the interface section.

type
  TBuilder = class
  private
    type
      TInterfaceImpl<T> = class(TInterfacedObject, IGenInterface<T>)
      public
        function TestGet: T;
      end;
  public
    class function Build<T>: IGenInterface<T>;
  end;

Or inside the other class:

type
  TBuilder<T> = class
  private
    type
      TInterfaceImpl = class(TInterfacedObject, IGenInterface<T>)
      public
        function TestGet: T;
      end;
  public
    class function Build: IGenInterface<T>;
  end;

Upvotes: 6

Related Questions