Recent

Author Topic: "Identifier idents no member" when using "implements" keyword  (Read 403 times)

PawelO

  • New Member
  • *
  • Posts: 31
    • Polish railway traffic and interlocking simulator developed with Lazarus
Hello,

Code: Pascal  [Select][+][-]
  1. {$interfaces corba}
  2.  
  3. IMyInterface = interface
  4.   ['IMyInterface']
  5.   procedure DoStuff;
  6. end;
  7.  
  8. TClassA = class(IMyInterface)
  9.   procedure DoStuff;
  10. end;
  11.  
  12. TClassB = class(IMyInterface)
  13. private
  14.   FClassA: TClassA;
  15. public
  16.   constructor Create;
  17.   destructor Destroy; override;
  18.   property ClassA: TClassA read FClassA implements IMyInterface;
  19. end;

TClassA implements an interface. TClassB implements same interface using TClassA with "implements" keyword. Lazarus code completion shows DoStuff as available TClassB method. However this:

Code: Pascal  [Select][+][-]
  1. var
  2.   classB: TClassB;
  3.  
  4. classB.DoStuff;

Causes compilation error:

Error: identifier idents no member "DoStuff"

It works only after casting to interface type:

Code: Pascal  [Select][+][-]
  1. var
  2.   classB: TClassB;
  3.   myInterface: IMyInterface;
  4.  
  5. myInterface := classB;
  6. myInterface.DoStuff;

Is this a bug or it should work that way by design?

Thaddy

  • Hero Member
  • *****
  • Posts: 19498
  • Glad to be alive.
Re: "Identifier idents no member" when using "implements" keyword
« Reply #1 on: June 05, 2026, 08:10:14 am »
It is not a bug. The classes need to be derived from TInterfacedObject.
You also can't use CORBA interfaces, because of that: it needs queryinterface, addref and release implemented.
Complete example:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$interfaces com}{$endif}
  2. uses classes;
  3. type
  4. IMyInterface = interface
  5. ['{2D9E9882-BB2F-4AB7-880D-4B82C2C4C425}']
  6.   procedure DoStuff;
  7. end;
  8.  
  9. TClassA = class(TInterfacedObject,IMyInterface)
  10.   procedure DoStuff;
  11. end;
  12.  
  13. TClassB = class(TInterfacedObject,IMyInterface)
  14. private
  15.   FClassA: IMyInterface;
  16. public
  17.   constructor Create(const AValue:IMyInterface);virtual;
  18.   property ClassA: IMyInterface read FClassA implements IMyInterface;
  19. end;
  20.  
  21. procedure TClassA.DoStuff;
  22. begin
  23.   writeln('Whatever I have to do');
  24. end;
  25.  
  26. constructor TClassB.Create(const aValue:IMyInterface);
  27. begin
  28.   inherited create;
  29.   FClassA := aValue;
  30. end;
  31.  
  32. var
  33.   test:IMyInterface;
  34. begin
  35.   test := TClassB.Create(TClassA.Create);// both created as IMyInterface, not as class
  36.   test.DoStuff; // delegates to ClassA through QueryInterface, hence COM not CORBA
  37. end.
Above also compiles in Delphi. Don't use CORBA with delegates.
« Last Edit: June 05, 2026, 03:27:06 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12561
  • Debugger - SynEdit - and more
    • wiki
Re: "Identifier idents no member" when using "implements" keyword
« Reply #2 on: June 05, 2026, 03:28:35 pm »
His issue is that he can't call

   The_Class_declared_var.MethodOfInterface;  // <= this will not cast to interface

The class could have any number of interfaces, so it wouldn't even be clear wich intf to cast to.

You have to either put the The_Class_declared_var in a typecast to the interface type you want, or assign it to a variable declared as the interface type and use that var.




Afaik, it is intended behaviour (and no bug) that

   The_Class_declared_var.MethodOfInterface;

does not work (so long as the class does not have its own method of name "MethodOfInterface" in scope.

And afaik that behaviour is the same for both types of interface.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12561
  • Debugger - SynEdit - and more
    • wiki
Re: "Identifier idents no member" when using "implements" keyword
« Reply #3 on: June 05, 2026, 03:29:16 pm »
Maybe use "type helper" instead...

Thaddy

  • Hero Member
  • *****
  • Posts: 19498
  • Glad to be alive.
Re: "Identifier idents no member" when using "implements" keyword
« Reply #4 on: June 05, 2026, 03:38:12 pm »
@Martin_fr

I know!! what the issue is, therefor I wrote a proper example based on his own code.
Although it also exposes a bug in FPC compared to Delphi: FPC leaks, Delphi NOT.
- this is a very, very old bug and known for "implements"-
And NO, it doesn't work alike for both interface types: QueryInterface is a COM concept and called internally.
You can solve that for CORBA by implementing QueryInterface manually.
CORBA interfaces are raw interfaces and do not rely on some infrastructure. COM interfaces expect IInterface fully implemented (QueryInterface, Addref and release)

I will fix the leak. There is a way and keeps compatibility with Delphi too.
A correct CORBA example would take many more lines of code. Silly concept.
« Last Edit: June 05, 2026, 03:53:58 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

PawelO

  • New Member
  • *
  • Posts: 31
    • Polish railway traffic and interlocking simulator developed with Lazarus
Re: "Identifier idents no member" when using "implements" keyword
« Reply #5 on: June 05, 2026, 03:50:27 pm »
Thanks for answers. I don't use COM interfaces as they adds life management through reference counting, and I don't want that - I need to add pure interfaces to simplify cooperation between objects, freeing is already done in another way.

Thaddy

  • Hero Member
  • *****
  • Posts: 19498
  • Glad to be alive.
Re: "Identifier idents no member" when using "implements" keyword
« Reply #6 on: June 05, 2026, 03:55:18 pm »
That is not possible with CORBA unless you implement QueryInterface for your classes.
You can skip addref and release, but QueryInterface is essential if you want to use "implements".

I can write an example if you wish, again based on your original code. I hate CORBA because it is useless without a broker like Midas, but you can code for it.

If you want to use "implements" you should be able to write code to examine the interface table and that is what QueryInterface does. Or just cheat and match your GUID/String.
« Last Edit: June 05, 2026, 04:05:54 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

PawelO

  • New Member
  • *
  • Posts: 31
    • Polish railway traffic and interlocking simulator developed with Lazarus
Re: "Identifier idents no member" when using "implements" keyword
« Reply #7 on: June 05, 2026, 04:15:49 pm »
Thanks, I usually cast to interface type instead of calling interface methods directly on class reference anyway, so it's not a big deal. I was just wondering why this example doesn't work, especially when IDE suggests it is valid (after typing "classB." it shows interface methods among class methods).

Thaddy

  • Hero Member
  • *****
  • Posts: 19498
  • Glad to be alive.
Re: "Identifier idents no member" when using "implements" keyword
« Reply #8 on: June 06, 2026, 05:43:52 am »
Does that mean I have the weekend off?  8-)

[edit] Added CORBA too, again based on your own code.[/edit]

The first example leaks in FPC and not in Delphi.
Here a leak-free version - both FPC and Delphi - that uses TAggregatedObject.
TClassA has no refcounting, the controller, TClassB does that:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$interfaces com}{$endif}
  2. uses classes;
  3. type
  4.  
  5.   IMyInterface = interface
  6.   ['{2D9E9882-BB2F-4AB7-880D-4B82C2C4C425}']
  7.     procedure DoStuff;
  8.   end;
  9.  
  10.   TClassA = class(TAggregatedObject ,IMyInterface)
  11.     procedure DoStuff;
  12.   end;
  13.  
  14.   TClassB = class(TInterfacedObject,IMyInterface)
  15.   private
  16.     FClassA: TClassA;
  17.   public  
  18.     constructor Create;
  19.     destructor destroy;override;
  20.     property ClassA: TClassA read FClassA implements IMyInterface;
  21.   end;
  22.  
  23. procedure TClassA.DoStuff;
  24. begin
  25.   writeln('Whatever I have to do');
  26. end;
  27.  
  28. constructor TClassB.Create;
  29. begin
  30.   inherited create;
  31.   FClassA:= TClassA.Create(self as IInterface);
  32. end;
  33.  
  34. destructor TClassB.Destroy;
  35. begin
  36.   FClassA.Free;
  37.   inherited destroy;
  38. end;
  39.  
  40. var
  41.   test:IMyInterface;
  42. begin
  43.   test := TClassB.Create;// Created as IMyInterface, not as class
  44.   test.DoStuff; // delegates to ClassA through QueryInterface, hence COM not CORBA
  45. end.

Will add a CORBA version later.
Done
Corba version:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$endif}
  2. {$interfaces corba}
  3. type
  4.   IMyInterface = interface
  5.   ['WhyUseCorba']
  6.     procedure DoStuff;
  7.   end;
  8.  
  9.   TClassA = class(IMyInterface)
  10.   public    
  11.     procedure DoStuff;
  12.   end;
  13.  
  14.    
  15.   TClassB = class(TObject, IMyInterface)
  16.   private
  17.     FClassA: TClassA;
  18.   public
  19.     constructor create;
  20.     destructor destroy;override;
  21.     property MyInterface: TClassA read FClassA implements IMyInterface;
  22.   end;
  23.  
  24.   procedure TClassA.Dostuff;
  25.   begin
  26.     writeln('Whatever I have to do');
  27.   end;
  28.  
  29.   constructor TCLassB.Create;
  30.   begin
  31.     inherited create;
  32.     FClassA := TClassA.Create;
  33.   end;
  34.  
  35.   destructor TClassB.Destroy;
  36.   begin
  37.     FClassA.Free;
  38.     inherited destroy;
  39.   end;
  40.    
  41. var
  42.   MyClass: TClassB;
  43.   MyInterface: IMyInterface;
  44. begin
  45.   MyClass := TClassB.Create;
  46.   MyInterface := MyClass;
  47.   MyInterface.DoStuff;
  48.   MyClass.Free;
  49. end.
Much simpler than I thought. "implements" is sufficiently implemented for CORBA nowadays.
You still can't use as though, just hard casts (ugly):
Code: Pascal  [Select][+][-]
  1. var
  2.   MyClass: TClassB;
  3. begin
  4.   MyClass := TClassB.Create;
  5.   IMyInterface(MyClass).DoStuff;
  6.   MyClass.Free;
  7. end.
CORBA does not compile in Delphi.
But for people who want delegates and CORBA the above should provide a correct example.
« Last Edit: June 06, 2026, 02:35:40 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

 

TinyPortal © 2005-2018