Discussion:
Question about generics and TLists
(too old to reply)
Ikke
2011-02-08 21:46:37 UTC
Permalink
Hi everybody,

Just a quick question about generics and TLists. There are two classes,
TSomething and TOther, as follows:
TSomething = Class(TItem)
TOther = Class(TItem)

In another class, I hold a TList<TSomething> and a TList<TOther>. There
are many more lists, but for simplicity, I've only just used these two.

TSomething and TOther share some functionality (hence the TItem class),
but both are rather different, so I'd like to keep them in separate
lists.

However, when I want to display them in a number of grids (each in their
own grid), I wanted to pass these to a single procedure, defined as:
procedure FillGrid(sg : TStringGrid; items : TList<TItem>);

This gave me an error of 'incompatible types'. Does this mean I have to
manually fill a new TList<TItem>? Or is there another way?

I'm assuming here that (if a TSomething is a TItem) a TList<TSomething>
is a TList<TItem>, but that is apparently not the case...

Is there an easy solution for this problem, instead of having to write
different fill procedures for different classes?

Thanks in advance!

Ikke
Maarten Wiltink
2011-02-09 13:53:57 UTC
Permalink
Post by Ikke
Just a quick question about generics and TLists. There are two classes,
TSomething = Class(TItem)
TOther = Class(TItem)
In another class, I hold a TList<TSomething> and a TList<TOther>. There
are many more lists, but for simplicity, I've only just used these two.
TSomething and TOther share some functionality (hence the TItem class),
but both are rather different, so I'd like to keep them in separate
lists.
However, when I want to display them in a number of grids (each in their
procedure FillGrid(sg : TStringGrid; items : TList<TItem>);
This gave me an error of 'incompatible types'. Does this mean I have to
manually fill a new TList<TItem>? Or is there another way?
I'm assuming here that (if a TSomething is a TItem) a TList<TSomething>
is a TList<TItem>, but that is apparently not the case...
Is there an easy solution for this problem, instead of having to write
different fill procedures for different classes?
Your idea is called covariance or contravariance, I'm not sure which
exactly, and it's valid... up to a point. Your list of TSomething cannot
blindly be used as a list if TItem, because adding a TOther to it would
be valid under the new type, but not under the old. It's essentially the
same problem as why the types of var parameters must match _exactly_.

You could use a Visitor to minimise the duplicated code.

(Compliments on having this problem in the first place.)

Groetjes,
Maarten Wiltink
JJ
2011-02-09 14:21:17 UTC
Permalink
Declare it as pointer instead:
procedure FillGrid(sg : TStringGrid; items : pointer);

then typecast it within the procedure:

procedure FillGrid(sg : TStringGrid; items : pointer);
begin
.
.
with TList(items) do
begin
.
.
end;
.
.
end;
Post by Ikke
Hi everybody,
Just a quick question about generics and TLists. There are two classes,
TSomething = Class(TItem)
TOther = Class(TItem)
In another class, I hold a TList<TSomething> and a TList<TOther>. There
are many more lists, but for simplicity, I've only just used these two.
TSomething and TOther share some functionality (hence the TItem class),
but both are rather different, so I'd like to keep them in separate
lists.
However, when I want to display them in a number of grids (each in their
procedure FillGrid(sg : TStringGrid; items : TList<TItem>);
This gave me an error of 'incompatible types'. Does this mean I have to
manually fill a new TList<TItem>? Or is there another way?
I'm assuming here that (if a TSomething is a TItem) a TList<TSomething>
is a TList<TItem>, but that is apparently not the case...
Is there an easy solution for this problem, instead of having to write
different fill procedures for different classes?
Thanks in advance!
Ikke
Loading...