[fpc-devel] Library announcement: Generics.Collections

Sven Barth pascaldragon at googlemail.com
Thu May 23 12:55:05 CEST 2013


Am 23.05.2013 12:22, schrieb Maciej Izak:
>
>
>
>     Nice. Now I know where all those bug reports come from :P
>
>
>  :D It's my pleasure. Aren't you happy?
Depends. On the one hand I'm happy that someone stresses the generics 
implementation to its limits (like JC Chu does as well), but on the 
other hand it means work in - in case of generics - a bunch of 
headaches... ;)
>
>     Are those available in Delphi as well? If not I see no use in them. 
>
>     Consider this code:
>
>     === code begin ===
>
>     procedure SomeProc(aValue: Int32);
>     var
>       p: Pointer;
>     begin
>        p := GetReferenceToValue(aValue);
>     end;
>
>     === code end ===
>
>     The value stored in "p" will be of no significant use for you to
>     be stored in the longterm, because aValue will be located on the
>     stack and thus the pointer will no longer be valid once the
>     function exits. This will also be the case for strings, arrays,
>     records, etc. No compiler magic will change this.
>
>
> Yes, I know that. I need this only for shortterm. In that case for 
> safety maybe we should remove System.Addr? ;) In Delphi they do that 
> by special interfaces created for each type (lost of time and memory). 
> First, I can't implement this by Delphi way because we have still a 
> lot of generics bugs. Secondly, I think that we can do much more 
> better implementation of Generics. This is not C#, in Pascal we have 
> better access to pointers. Now I'm using (I hope temporarily):
>
> === code begin ===
>
>   TValueAnsiStringHelper = record helper for AnsiString
>     function GetValueSize: Integer; inline;
>     function GetReferenceToValue: Pointer; inline;
>   end;
>
> function TValueAnsiStringHelper.GetValueSize: Integer;
> begin
>   Result := Length(Self) * SizeOf(AnsiChar);
> end;
>
> function TValueAnsiStringHelper.GetReferenceToValue: Pointer;
> begin
>   if Length(Self) <> 0 then
>     Result := @Self[1]
>   else
>     Result := nil;
> end;
>
>  === code end ===
> Etc. for other basic types.
>
> I, really need this for custom comparers and equality comparers, for 
> example:
>
> === code begin ===
> while AComparer.Compare(AValues[I].GetReferenceToValue, 
> P.GetReferenceToValue, AValues[I].GetValueSize, P.GetValueSize) < 0 do
> // ...
> if FEqualityComparer.Equals(AKey.GetReferenceToValue, 
> LItem.Pair.Key.GetReferenceToValue, AKey.GetValueSize, 
> LItem.Pair.Key.GetValueSize) then
>  === code end ===

I still see no need for this. I would simply do

=== code begin ===

if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then
   ...

=== code end ===

Why fall back to pointers for something like this if we can use static 
types?! And if that means that the comparer needs to be implemented for 
each type, then so be it (you could implement a default generic 
comparer, which uses the normal "=" operator, maybe some others for 
basic types like strings and a TObject.Equals based one and the other 
comparators should be supplied by the user). You can't do things as 
equality tests in a general way anyway (best example: case sensitive vs. 
case insensitive comparison of strings). If your concern is performance 
then you could declare the two parameters as "constref" so that they are 
passed by reference and not by value.

>
>         measured by human/programmer
>           function GetValueSize(Value: T): Integer; // for string
>         types return Length(s), for Int32 returs 4 etc.
>
>     You should not store the string's content, but only the reference
>     to the string. If you use assignment operators the RTL will take
>     care of the rest.
>
>
> But with generics code for some types i don't have predefined 
> operators (for example: records), and here is the problem with 
> Generics Dictionary.
If your implementation of Generics.Dictionary needs certain operators 
than the type with which the dictionary is specialized needs to 
implement these operators. If the type does not: bad luck.
> GetValueSize and GetReferenceToValue is in the same level as 
> System.SizeOf and System.Addr.
>
> I think it's a natural evolution System.SizeOf and System.Addr for 
> Generics (to operate on values).
I see no need for a context sensitive SizeOf and your 
GetReferenceToValue is simply flawed, because you can't capture the 
correct location of a parameter passed by value as this is just a copy, 
no "@Self" will result in the correct value here. E.g.:

=== code begin ===

{$mode objfpc}

type
   TLongIntHelper = type helper for LongInt
     function GetSelfAddress: Pointer;
   end;

function TLongIntHelper.GetSelfAddress: Pointer;
begin
   Result := @Self;
end;

var
   l: LongInt;

procedure TestProc(aValue: LongInt);
begin
   Writeln(hexstr(aValue.GetSelfAddress));
   Writeln(hexstr(l.GetSelfAddress));
end;

begin
   l := 42;
   Writeln(hexstr(l.GetSelfAddress));
   TestProc(l);
end.

=== code end ===

=== output begin ===

0040B000
0140FE4C
0040B000

=== output end ===

> There is no other language as FreePascal and it would be wrong to 
> introduce something stupid to such an important system functions. If 
> my thinking is wrong, please, any hint of an alternative. Without it, 
> I'm completely stuck.

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20130523/20a94c95/attachment.html>


More information about the fpc-devel mailing list