How to make the specialized generics TGenClassA and TGenClassB related?
like it would be something like
type TGenClassB = class(TGenClassA) specialize TGenClass<TClassB>
Or make proc() a member of TGenClass?
construct a nice class hierarchy or work with interfaces if you need something specific.
A TGenClass<TClassA> can contain other descendants of TClassA which could lead to problems with accessing them as a TGenClass<TClassB>. And even the other way round (as you have it) can lead to problems, for example if non-virtual methods are called inside the generic.
that how it was in my code for FPC3.0. In FPC 3.2 it is not allowed.No not the typecast , but my code works (very recent trunk, as usual)
project1.lpr(31,27) Error: Generics without specialization cannot be used as a type for a variable
QuoteA TGenClass<TClassA> can contain other descendants of TClassA which could lead to problems with accessing them as a TGenClass<TClassB>. And even the other way round (as you have it) can lead to problems, for example if non-virtual methods are called inside the generic.
Here I do not understand. If in other places of program I can define a variable V:TClassA and then assign TClassB instance to it and use it, why a generic specialized to TClassA cannot do it? The var V is also sort of "specialized" to TClassA, but it can do it.
Ideally compiler should know, if I specialize generics by related classes these generics should be somewhat related. Not completely unrelated.
It should check generic methods how they use specialized fields/methods/properties etc...
But it is not done this way. Yet. May be it will be in FPC4? :)
So, what would be a solution?
Why do you need to access a list of TClassB as a list of TClassA? Breaking the type system usually means that you have a conceptual problem in your code.
I disagree. In my case nothing is wrong. It is not breaking the system. It is using OOP polymorphism.Because polymorphism works for objects themselves, but not for object containers.
It is completely legitimate to use single var of type TClassA to assign and work with an instance of its descendant class TClassB.
Why lists of vars of TClassA should be different in this regard?
I disagree. In my case nothing is wrong. It is not breaking the system. It is using OOP polymorphism.Because polymorphism works for objects themselves, but not for object containers.
It is completely legitimate to use single var of type TClassA to assign and work with an instance of its descendant class TClassB.
Why lists of vars of TClassA should be different in this regard?TGenClassB should be directly inherited from TGenClassA.(Doesn't work anyway) Casting one container to another - is what is considered to be hack, i.e. isn't guaranteed to work. Adding TClassB to container for TClassA is ok. Casting TClassB container to TClassA container isn't. Right use of polymorphism is - to use TClassA container and add TClassB objects to it or, if it's not possible, provide some interface, that will cast TClassB to TClassA internally.
Another variant - if you don't want to add it to TGenClass, make "proc" generic too, i.e. "procedure proc<T>(AGenClass:TGenClass<T>);". Delphi can do it. Not sure about FPC.
program ProcGeneric; {$mode ObjFPC} type generic TMyList<ItemType> = class storage: array of ItemType; procedure add(aItem:ItemType); end; procedure TMyList.Add(aItem:ItemType); begin setLength(storage, length(storage)+1); storage[length(storage)-1] := aItem; end; type TClassA = class end; TClassB = class(TClassA) end; TMyListA = specialize TMyList<TClassA>; TMyListB = specialize TMyList<TClassB>; TListUser = class generic procedure UseList<ListType>(aList: ListType); end; generic procedure TListUser.UseList<ListType>(aList: ListType); var b:TClassB; begin b:=TClassB.Create; aList.Add(b); end; generic procedure GlobalUseList<ListType>(aList: ListType); var b:TClassB; begin b:=TClassB.Create; aList.Add(b); end; var MyListA: TMyListA; ListUser: TListUser; begin MyListA := TMyListA.Create; ListUser:= TListUser.Create; specialize GlobalUseList<TMyListA>(MyListA); specialize ListUser.UseList<TMyListA>(MyListA); //Fatal: Syntax error, "<" expected but "." found end.
It works for GlobalUseList, but does not work for for class method call.