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;


_______________________________________________
fpc-devel maillist  -  [email protected]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to