[Lazarus] Generics type as parameter

Sven Barth pascaldragon at googlemail.com
Sun May 13 18:19:25 CEST 2012


On 13.05.2012 17:10, Leonardo M. Ramé wrote:
> On 2012-05-13 13:38:36 +0200, Sven Barth wrote:
>> On 13.05.2012 12:46, Leonardo M. Ramé wrote:
>>> On 2012-05-13 10:53:42 +0200, Sven Barth wrote:
>>>> On 13.05.2012 02:49, Leonardo M. Ramé wrote:
>>>>> On 2012-05-12 13:07:18 -0300, Leonardo M. Ramé wrote:
>>>>>> Thanks Sven and Michalis. Using the suggestion by Michalis, I got a
>>>>>> solution mixing Generics and regular objects.
>>>>>>
>>>>>> What I'm pursuing is to replace my TCollection based ORM, with a
>>>>>> Generics based one, this allow users to write less code, in a clearer
>>>>>> way.
>>>>>>
>>>>>> The way the ORM works, is to create a TCollection instance, then execute
>>>>>> an ORM's method to load/save data into/from it, example:
>>>>>>
>>>>>> var
>>>>>>    lCustomers: TCustomers; // this is a TCollection descendant
>>>>>> begin
>>>>>>    lCustomers := TCustomers.Create;
>>>>>>    FConnector.LoadData(lCustomers, []);
>>>>>>    ... do something with lCustomers ...
>>>>>>    lCustomers.Free;
>>>>>> end;
>>>>>>
>>>>>> As you can see, FConnector.LoadData receives a TCollection as parameter,
>>>>>> and using RTTI, it fills each TCustomer published property.
>>>>>>
>>>>>> With Michalis's solution, I can turn my ORM from TCollections to
>>>>>> Generics with very little changes, see how small is the unit customer
>>>>>> now, instead of a complete TCollection/TCollectionItem definition:
>>>>>>
>>>>>
>>>>> Following the same subject, inside a method receiving an TFPSList, how
>>>>> can I know the type of items it will contain, even if the list is
>>>>> empty?.
>>>>>
>>>>> In a TCollection, I can use myCollection.ItemClass to know it, but in a
>>>>> specialized Generic type, how can I know, in an abstract way the type of
>>>>> a TFPGList<T>?. I mean, what type is T?.
>>>>
>>>> You can't. That's why the method with the "parent class" might be considered
>>>> less powerful than the one with generic methods/procedures.
>>>>
>>>> Regards,
>>>> Sven
>>>>
>>>
>>> Hm. Another thing I'm stuck on, is specialized classes doesn't seem to
>>> have a ClassName, am I righ?.
>>>
>>
>> Specialized classes are just normal classes. They DO have a class name, but
>> it is not the one that you might expect.
>>
>> Following example:
>>
>> === example begin ===
>>
>> type
>>    TTest<T>  = class
>>
>>    end;
>>
>>    TTest1 = specialize TTest<LongInt>;
>>    TTest2 = specialize TTest<LongInt>;
>>
>> begin
>>    with TTest1.Create do
>>      try
>>        Writeln(ClassName);
>>      finally
>>        Free;
>>      end;
>>    with TTest2.Create do
>>      try
>>        Writeln(ClassName);
>>      finally
>>        Free;
>>      end;
>> end.
>>
>> === example end ===
>>
>> In both cases the same name "TTest$1$crc31B95292" will be written which is
>> composed out of the name of the generic (which is "TTest$1", where the "$1"
>> stands for "has one generic parameter") and the crc of the given type
>> parameters. This name is an implementation detail though, so DO NOT RELY ON
>> IT, because I WILL change it sooner or later (to be more like
>> "TTest<System.LongInt>").
>>
>> The fact that the name is in both cases the same is because the generic is
>> only specialized once per unit, so that code like the following can find the
>> correct specialization (this works in mode Delphi):
>>
>> === example begin ===
>>
>> var
>>    t: TTest<LongInt>;
>> begin
>>    t := TTest<LongInt>.Create;
>>    try
>>      t.Value := TTest<LongInt>.SomeConstant;
>>    finally
>>      t.Free;
>>    end;
>> end.
>>
>> === example end ===
>>
>> Regards,
>> Sven
>>
>
> Ok, so, what happens if I declare the same specialization in different
> units, then pass instances of each specialization to the same method,
> its ClassName should be the same, no?.

Yes, though currently a TFPGList<LongInt> declared in different units 
won't be compatible to each other (it's planned to change this).

>
> for example:
>
> ----
> unit1;
> ...
> type
>    TCustomers = specialize TFPGList<TCustomer>;
> -----
> ----
> unit2;
> ...
> type
>    TCustomers_from_branch1 = specialize TFPGList<TCustomer>;
> -----
>
> What I would like, is, when I ask for the instance's classname, it write
> TCustomers and TCustomers_from_branch1, instead of TFPGList$1$....
>
> Is this planned?.
>

No, this won't be possible. As I said the class name that is used is 
based on the "specialize ..." part. The type name on the left is only an 
alias to that specialization type.

Regards,
Sven




More information about the Lazarus mailing list