[fpc-devel] interfaces / inheritance / again

Martin Frb lazarus at mfriebe.de
Tue Feb 3 00:59:20 CET 2026


On 02/02/2026 22:59, Michael Van Canneyt via fpc-devel wrote:
>
>
> Perhaps stupid question: why don't you use a generic IFoo<T> ?

Because I can't use that as constraint to the generic that requires the 
different return types.

If I drop the constraints, then I can just use independent interfaces...
But then still, each interface has a
   function    GetItem: TSomeType;  // diff type for each interface

And the generic will call that GetItem, on all of them. Not much difference.



>
> I read your technical solution to a problem: all that is clear to me 
> is that
> you want to use generics and interfaces to mix lists, but I did not 
> understand the original problem: why do you need these lists, what is 
> their purpose
> etc.

See sample at the end... May have some issues. I had to rewrite it 
countless times. I do have to double check that the current version 
makes sense.

I will then have different list, that can be synced.

Some of them have refcounting items. In that case the code in an 
inherited method "UpdateEntryAt" must be able to access
   data_of_type_SRC_ENTRY.AddReference

Of course I can
   specialize TDbgSynchronizedListTemplate<TOBject, _LIST, 
IIntfForItemWithAddRef>

But then if
   List.Entries does not return the type IIntfForItemWithAddRef
that is where the problem is.

I can specialize the generic with the correct inherited interface. But 
that interface will have
   _LIST.Entries[i]
called.
The name "Entries" is hard coded, I can not change that.
(Oh, yes, add a virtual method "function GetEntry: _SRC_ENTRY; virtual", 
and override it in each specialization. Not really, what I was looking for.




>
> Maybe you don't need lists at all. Maybe a simple iterator or visitor
> pattern suffices, and you would not have the complexity you introduce 
> by using lists. 
The lists will contain data for the debugger.  Each backend will have a 
list. And the frontend will have one.

So there is my need for interfaces, allowing me to separate the backend 
and frontent.
The backends need copies, so they can keep old data until they processed 
the new. Or they may have to make copies to be handled in threads...

So currently I only have one set of data...  (yet already storage with 
and without refcounting)
But the concept of such a list, is generally useful, and I can see it 
being used more on the long run... So I do want to separate the "sync" 
concept, and the payload.

Also depending on other payloads, the storage implementation may vary: 
list, hash ....


------------------------------------------------------------

2 (or a chain of more than 2) lists, that can sync to updates of the 
"origin" (or multiple origin lists).

Entries are marked with a global change stamp. So lists only need to 
update entries that are changed, new or gone.
(meaning for other entries, there is no search for the copied entry, 
saving time)

The "receiving" class is based on the generic.
it can itself also implement the interface, do allow forward sync to yet 
another receiver.



type

   (* About the ChangeStamp:

      Each type should have one global source for the ChangeStamp.
      If any entry changes, it should get a new value, that therefore is 
newer
      than any known value by any list that may exist (and that may 
compare to
      the entries ChangeStamp)

      If a List updates it can either set its own ChangeStamp to the 
highest seen
      value in all entries, or to the current global value.

      If an entry is added/removed to/from a list (that can be source 
for sync)
      then that entry must update its ChangeStamp (even if it had no 
changes of
      its own).
      That way it will be noted as new by any list that may synchronize 
from it,
      even if that list had not known the entry before.

      If a list is not used a source for sync, then add/remove of 
entries does not
      need to update the entries ChangeStamps
   *)

   IDbgSynchronizedListEntryIntf = interface 
['{A05705C7-7443-43A0-9B32-EDAD5D888051}']
     function  GetID: QWord;
     function  GetChangeStamp: QWord;
     function  IsDeleted: boolean;      // check in source list, remove 
in target

     property ID: QWord read GetID;
     property ChangeStamp: QWord read GetChangeStamp;
   end;

   IDbgSynchronizedListIntf = interface 
['{3DA08DFE-B061-499C-9FA0-8ECA57F19496}']
     function  Count: Integer;
     function  GetSyncEntry(AnIndex: Integer): 
IDbgSynchronizedListEntryIntf;
     function  GetChangeStamp: QWord;

     property Entries[AnIndex: integer]: IDbgSynchronizedListEntryIntf 
read GetSyncEntry; default;
     property ChangeStamp: QWord read GetChangeStamp;
   end;

   { TDbgSynchronizedListTemplate }

   generic TDbgSynchronizedListTemplate<
     _BASE: class;
     _SRC_LIST: IDbgSynchronizedListIntf;
     _SRC_ENTRY: IDbgSynchronizedListEntryIntf
   > = class(_BASE)
   private
     procedure UpdateOwnCountAfterDelete(AnOwnCount: integer); virtual;
   protected
     function  GetIndexOfId(AnID: QWord): Integer; virtual; abstract;

     procedure AddEntryFor(AnSource: _SRC_ENTRY); virtual; abstract;
     procedure UpdateEntryAt(AnIndex: integer; AnSource: _SRC_ENTRY); 
virtual; abstract;
     procedure DeleteEntryAt(AnIndex: integer; AnSource: _SRC_ENTRY); 
virtual; abstract;

     procedure UpdateListFrom(ASourceList: _SRC_LIST; AnOwnCount: 
integer; var AnOwnChangeStamp: QWord);
   end;




More information about the fpc-devel mailing list