[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