Discussion:
[fpc-pascal] Generic type parameter variable initialization
kyan
2012-01-05 10:57:35 UTC
Permalink
Hello everybody.

I am new to FPC/Lazarus and I am trying to port some Delphi XE code
that uses the units Generics.Defaults and Generics.Collections so I
have to write these units for FPC because they do not exist and the
code I am porting relies heavily on them. In this process I have come
across various issues with Delphi/FPC generic compatibility but I have
managed to overcome most of them.

In a method of a generic class I need to initialize a variable of type
"T" (the generic class type parameter) with the type T's "default"
value, which is 0 for ordinal types, '' for strings, nil for
pointers/classes/interfaces, Unassigned for Variants etc. In Delphi
there is the "compiler magic" function Default() and you can write:

procedure TMyClass<T>.SomeMethod;
var
  V: T;
begin
  ...
  V := Default(T);
  ...
end;

This does not compile in FPC. Is there an alternative in FPC for the
function Default()? I suppose one could do this:

procedure TMyClass<T>.SomeMethod;
var
  V: T;
begin
  ...
  Finalize(V);
  FillChar(V, SizeOf(V), 0);
  ...
end;

which is equivalent but it doesn't look too elegant. I am using FPC
2.7.1 for Win32/64.

Thank you in advance,

Constantine.
Sven Barth
2012-01-05 13:19:40 UTC
Permalink
Post by kyan
Hello everybody.
I am new to FPC/Lazarus and I am trying to port some Delphi XE code
that uses the units Generics.Defaults and Generics.Collections so I
have to write these units for FPC because they do not exist and the
code I am porting relies heavily on them. In this process I have come
across various issues with Delphi/FPC generic compatibility but I have
managed to overcome most of them.
If there are compatibility problems that are not yet mentioned in the
bugtracker at http://bugs.freepascal.org/ it would be nice if you'd
report them.
Post by kyan
In a method of a generic class I need to initialize a variable of type
"T" (the generic class type parameter) with the type T's "default"
value, which is 0 for ordinal types, '' for strings, nil for
pointers/classes/interfaces, Unassigned for Variants etc. In Delphi
procedure TMyClass<T>.SomeMethod;
var
V: T;
begin
...
V := Default(T);
...
end;
This does not compile in FPC. Is there an alternative in FPC for the
This functionality does not exist yet. See also here:
http://bugs.freepascal.org/view.php?id=9420
Post by kyan
procedure TMyClass<T>.SomeMethod;
var
V: T;
begin
...
Finalize(V);
FillChar(V, SizeOf(V), 0);
...
end;
which is equivalent but it doesn't look too elegant. I am using FPC
2.7.1 for Win32/64.
For now you'll need to use this workaround solution.

Regards,
Sven
Florian Klämpfl
2012-01-05 14:03:50 UTC
Permalink
Post by Sven Barth
Post by kyan
procedure TMyClass<T>.SomeMethod;
var
V: T;
begin
...
Finalize(V);
FillChar(V, SizeOf(V), 0);
...
end;
which is equivalent but it doesn't look too elegant. I am using FPC
2.7.1 for Win32/64.
For now you'll need to use this workaround solution.
Has the workaround really the same effect? I really wonder why there is
a need for default then ...
Sven Barth
2012-01-05 14:17:00 UTC
Permalink
Post by Florian Klämpfl
Post by Sven Barth
Post by kyan
procedure TMyClass<T>.SomeMethod;
var
V: T;
begin
...
Finalize(V);
FillChar(V, SizeOf(V), 0);
...
end;
which is equivalent but it doesn't look too elegant. I am using FPC
2.7.1 for Win32/64.
For now you'll need to use this workaround solution.
Has the workaround really the same effect? I really wonder why there is
a need for default then ...
It should at least be sufficent for the most common cases:
* ordinals
* strings
* classes
* records (and objects)

I don't know about Variants though. The Delphi help isn't helping either ;)

Regards,
Sven
kyan
2012-01-05 14:51:13 UTC
Permalink
Post by Florian Klämpfl
Has the workaround really the same effect? I really wonder why there is
a need for default then ...
Yes, works for Variants as well. Look at the implementation of
System._FinalizeArray() in Delphi; it handles tkVariant type kind.
Come to think of it, it can be elegantly wrapped up in the following
generic class:

type
 TDefault<T> = class
   class function Value: T; inline;
 end;

class function TDefault<T>.Value: T;
begin
 Finalize(Result);
 FillChar(Result, SizeOf(Result), 0);
end;

and used like this:

type
TSomeRec = record
S: string;
V: Variant;
I: Integer;
end;
var
 S: string;
 I: Integer;
 V: Variant;
 X: IInterface;
 C: TObject;
 D: TDateTime;
 R: TSomeRec;
 P: Pointer;
begin
 S := 'test';
 I := 42;
 V := Date;
 D := Date;
 X := Self;
 C := Self;
 R.S := 'test1';
 R.V := Date;
 R.I := 99;
 P := Self;

 S := TDefault<string>.Value;
 I := TDefault<Integer>.Value;
 V := TDefault<Variant>.Value;
 D := TDefault<TDateTime>.Value;
 X := TDefault<IInterface>.Value;
 C := TDefault<TObject>.Value;
 R := TDefault<TSomeRec>.Value;
 P := TDefault<Pointer>.Value;
end;
Sven Barth
2012-01-05 15:38:50 UTC
Permalink
Post by kyan
Post by Florian Klämpfl
Has the workaround really the same effect? I really wonder why there is
a need for default then ...
Yes, works for Variants as well. Look at the implementation of
System._FinalizeArray() in Delphi; it handles tkVariant type kind.
Saying a FPC compiler developer to look at the Delphi implementation is
problematic, because than we could get accused of copying code (which is
why I use the Delphi XE starter version which does not contain the
source code of the RTL and VCL).
Post by kyan
Come to think of it, it can be elegantly wrapped up in the following
While this does indeed look nicely it's still not Delphi compatible ;)

Regards,
Sven
kyan
2012-01-05 16:14:14 UTC
Permalink
Post by Sven Barth
Saying a FPC compiler developer to look at the Delphi implementation is
problematic, because than we could get accused of copying code (which is why
I use the Delphi XE starter version which does not contain the source code
of the RTL and VCL).
I am sorry, I wasn't aware of that. But by means of testing I found
that Finalize() works correctly for Variants in Lazarus as well. I
don't know about the internals much but I suppose the place to look in
FPC is procedure fpc_finalize() in objpas.inc which does handle
tkVariant as well.
Post by Sven Barth
While this does indeed look nicely it's still not Delphi compatible ;)
I think it is, it works in my Delphi XE exactly the way it does in
Lazarus. It is just not defined in Delphi's RTL. I meant it as a temp
solution until you implement Default() or something equivalent.

Anyway, let me not waste any more of your time. :)

Regards.
Sven Barth
2012-01-05 16:51:44 UTC
Permalink
Post by kyan
Post by Sven Barth
Saying a FPC compiler developer to look at the Delphi implementation is
problematic, because than we could get accused of copying code (which is why
I use the Delphi XE starter version which does not contain the source code
of the RTL and VCL).
I am sorry, I wasn't aware of that. But by means of testing I found
that Finalize() works correctly for Variants in Lazarus as well. I
don't know about the internals much but I suppose the place to look in
FPC is procedure fpc_finalize() in objpas.inc which does handle
tkVariant as well.
Hmm... the implementation of Default might not be that hard in the
end... if I find the time I might experiment with an implementation at
the weekend.
Post by kyan
Post by Sven Barth
While this does indeed look nicely it's still not Delphi compatible ;)
I think it is, it works in my Delphi XE exactly the way it does in
Lazarus. It is just not defined in Delphi's RTL. I meant it as a temp
solution until you implement Default() or something equivalent.
My sentence was meant like this: It looks nice and works in FPC and
Delphi, but it can not be used the same as Default. ;)

Regards,
Sven

Loading...