Recent

Author Topic: Trying to undertand interfaces used with generics  (Read 441 times)

vsajip

  • New Member
  • *
  • Posts: 26
Trying to undertand interfaces used with generics
« on: June 02, 2025, 09:40:43 am »
The following program won't compile:

Code: Pascal  [Select][+][-]
  1. {$mode ObjFPC}{$H+}
  2. {$interfaces corba}
  3.  
  4. program iface3;
  5.  
  6. uses Classes, FGL;
  7.  
  8. type
  9.   INameable = interface
  10.     function GetName: string;
  11.   end;
  12.  
  13.   TNameable = class(TObject, INameable)
  14.   protected
  15.     fName: string;
  16.   public
  17.     constructor Create(aName: string);
  18.     function GetName: string;
  19.   end;
  20.  
  21.   TINameableList = specialize TFPGList<INameable>;
  22.   TTNameableList = specialize TFPGList<TNameable>;
  23.  
  24. constructor TNameable.Create(aName: string);
  25. begin
  26.   fName := aName;
  27. end;
  28.    
  29. function TNameable.GetName: string;
  30. begin
  31.   Result := fName;
  32. end;
  33.  
  34. var
  35.   list1: TTNameableList;
  36.   list2: TINameableList;
  37. begin
  38.   list1 := TTNameableList.Create;
  39.   list2 := list1;
  40. end.

The error is

Code: Text  [Select][+][-]
  1. Free Pascal Compiler version 3.2.2 [2021/07/09] for x86_64
  2. Copyright (c) 1993-2021 by Florian Klaempfl and others
  3. Target OS: Linux for x86-64
  4. Compiling iface3.pas
  5. fgl.pp(1023,7) Note: Call to subroutine "function TFPGList<iface3.INameable>.Add(const Item:INameable):LongInt;" marked as inline is not inlined
  6. fgl.pp(1023,20) Note: Call to subroutine "function TFPGList<iface3.INameable>.Get(Index:LongInt):INameable;" marked as inline is not inlined
  7. fgl.pp(1023,7) Note: Call to subroutine "function TFPGList<iface3.TNameable>.Add(const Item:TNameable):LongInt;" marked as inline is not inlined
  8. fgl.pp(1023,20) Note: Call to subroutine "function TFPGList<iface3.TNameable>.Get(Index:LongInt):TNameable;" marked as inline is not inlined
  9. iface3.pas(41,12) Error: Incompatible types: got "TFPGList<iface3.TNameable>" expected "TFPGList<iface3.INameable>"
  10. iface3.pas(43) Fatal: There were 1 errors compiling module, stopping
  11. Fatal: Compilation aborted
  12. Error: /usr/bin/ppcx64 returned an error exitcode

Now, as TNameable is an INameable, it seems like an FPGList<INameable> should be able to be assigned an FPGList<TNameable>, as anything in the list will obey anything a FPGList<INameable> will expect. What would be the reason for disallowing such an assignment?

cdbc

  • Hero Member
  • *****
  • Posts: 2245
    • http://www.cdbc.dk
Re: Trying to undertand interfaces used with generics
« Reply #1 on: June 02, 2025, 10:06:49 am »
They are different types.
The 2 generic lists are NOT related, like the
Code: Pascal  [Select][+][-]
  1. type
  2.   INameable = interface
  3.     function GetName: string;
  4.   end;
  5.  
  6.   TNameable = class(TObject, INameable)
  7.   protected
  8.     fName: string;
  9.   public
  10.     constructor Create(aName: string);
  11.     function GetName: string;
  12.   end;
are.
These are 2 different types:
Code: Pascal  [Select][+][-]
  1.   TINameableList = specialize TFPGList<INameable>;
  2.   TTNameableList = specialize TFPGList<TNameable>;
ListItem -> ListItem, I'm not sure, IS / AS would help you, since your interfaces are defined as CORBA. Mind you; It wouldn't be any easier were they COM!
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

vsajip

  • New Member
  • *
  • Posts: 26
Re: Trying to undertand interfaces used with generics
« Reply #2 on: June 02, 2025, 10:41:54 am »
Quote
They are different types.

I get that they're different types, but the question is, why is the assignment disallowed, what problems could arise from allowing it? After all, INameable and TNameable are different types too, and one can be assigned to the other.

cdbc

  • Hero Member
  • *****
  • Posts: 2245
    • http://www.cdbc.dk
Re: Trying to undertand interfaces used with generics
« Reply #3 on: June 02, 2025, 11:12:25 am »
Yes, but you're assigning the lists to one another  :P
My advice, study interfaces and then generics, way more than you have so far!
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

PascalDragon

  • Hero Member
  • *****
  • Posts: 6033
  • Compiler Developer
Re: Trying to undertand interfaces used with generics
« Reply #4 on: June 02, 2025, 10:04:08 pm »
Quote
They are different types.

I get that they're different types, but the question is, why is the assignment disallowed, what problems could arise from allowing it? After all, INameable and TNameable are different types too, and one can be assigned to the other.

TNameable can be assigned to a INameable, because the compiler can do a suitable conversion from class instance to interface instance. However the compiler can not know how it should assign a TFPGList<TNameable> to a TFPGList<INameable>, because it has no knowledge about what that type does. It also wouldn't support assigning array of TNameable to array of INameable, because the compiler does not do mapping of single elements of an array for the whole array.
Of course you can always declare and implement a suitable operator overload... 🤷‍♀️

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11440
  • Debugger - SynEdit - and more
    • wiki
Re: Trying to undertand interfaces used with generics
« Reply #5 on: June 02, 2025, 10:30:56 pm »
To maybe clarify a bit more.
Code: Pascal  [Select][+][-]
  1. MyINameable := MyTNameable;

That is not just an assignment. That is a conversion.

If you look at the memory in each of the 2 variables, then MyINameable will not contain a copy of MyTNameable.
It will contain an interface.

The compiler retrieved that data (the interface) as part of the assignment. Hence its a conversion.




As for PascalDragons "array of" example. Here the compiler could in theory generate code to iterate the entire array and convert each value.
However the compiler does not. It simple isn't implemented in the compiler to do that.



When you take a TFPGList then the compiler actually can't even do the iterate. It couldn't do it, even if someone wanted to add that to the compiler.

It would need to trace all places where a TNameable might potentially be stored in that class, and it would need to convert them all.

However, IIRC some of those classes (and IIRC that includes TFPGList) just allocate memory. E.g. for storage they use something like either "Array of byte" or "PByte".
The code accesses that with the correct typecasts.
But if the compiler would want to figure out where it needs to convert some TNameAble, then it wouldn't know about PByte.

 

TinyPortal © 2005-2018