Why can't I pass a TObjectList<S: T> to a function expecting a TObjectList<T>?

delphi, generics, tobjectlist

Solution

In the function with the error, `Result` is a `TObjectList<T>`, where `T` is some subclass of `TItem`, but the compiler doesn't know what specific class it is. The compiler has to compile it so that it's safe to run for any value of `T`. That might not be compatible with the argument type of `LoadAll`, which requires a `TObjectList<TItem>`, so the compiler rejects the code.

Suppose `T` is `TItemDescendant`, and the compiler allows the faulty code to compile and execute. If `LoadAll` calls `AList.Add(TItem.Create)`, then `AList` will end up holding something that isn't a `TItemDescendant`, even though it's a `TObjectList<TItemDescendant>`. It holds an object of a type different from what its generic type parameter says it holds.

Just because `S` is a subtype of `T` doesn't mean that `X<S>` is a subtype of `X<T>`.

Problem

I have problem with my code, which uses generic types. Why doesn't the compiler know that the passed list (`Result`) is a `TObjectList<TItem>` (`TItem` is type for `T` in `TItems`)? Interface: ``` type TItem = class end; type IItemsLoader = interface procedure LoadAll(AList : TObjectList<TItem>); end; type TItemsLoader = class(TInterfacedObject, IItemsLoader) public procedure LoadAll(AList : TObjectList<TItem>); end; type IItems<T : TItem> = interface function LoadAll : TObjectList<T>; end; type TItems<T : TItem> = class(TInterfacedObject, IItems<T>) private FItemsLoader : TItemsLoader; public constructor Create; destructor Destroy; override; function LoadAll : TObjectList<T>; end; ``` Implementation: ``` procedure TItemsLoader.LoadAll(AList: TObjectList<TItem>); begin /// some stuff with AList end; { TItems<T> } constructor TItems<T>.Create; begin FItemsLoader := TItemsLoader.Create; end; destructor TItems<T>.Destroy; begin FItemsLoader.Free; inherited; end; function TItems<T>.LoadAll: TObjectList<T>; begin Result := TObjectList<T>.Create(); /// Error here /// FItemsLoader.LoadAll(Result); end; ```

Original source