Am 27.01.2012 16:23, schrieb Kornel Kisielewicz:
Hello all,
This my first mail to the list, and while this message might fit
fpc-pascal, I wasn't sure about it, due to the fact that it has
questions only a dev can answer, and possibly hints some bugs. Using
FPC 2.6.0 / Win32 on Windows 7/64.
fpc-pascal would have been ok as well (maybe even better, because it's
about usage of FPC...). Nevertheless the devs are normally subscribed to
at least fpc-pascal and fpc-devel.
So first of all, there's either a mistake in the manual, or FPC bug:
( following Ref 8.3 Generic class specialization )
{$MODE OBJFPC}
program generic_bug1;
type generic TList<T> = class x : T; end;
// Note that 2 specializations of a generic type with
// the same types in a placeholder are not assignment
// compatible. In the following example:
type
TA = specialize TList<Pointer>;
TB = specialize TList<Pointer>;
// variables of types TA and TB cannot be assigned to each
// other, i.e the following assignment will be invalid:
Var
A : TA;
B : TB;
begin
A:=B;
end.
Well it turns out it's not invalid at all. It compiles without
warnings, and if added surrounding sensible code, works all well.
Seems as the compiler treats TA and TB as the same types. However if
we define TA and TB in a different units it doesn't work anymore --
which isn't surprising. So either the manual should be updated, or the
"reusage" of the generic should be removed.
In my opinion the documentation should be updated, because in Delphi
(and FPC's mode Delphi in trunk) you use code like the following:
procedure Foo;
var
A: TList<Pointer>;
B: TList<Pointer>;
begin
A := TList<Pointer>;
B := A;
end;
So it would not make sense for A and B to be of different types as you
can also write
var
A, B: TList<Pointer>;
One might argue that
type
TA = specialize TList<Pointer>;
TB = specialize TList<Pointer>;
is something different, but I say it is not.
While this may seem very cosmetic, I found a case where it really
makes a difference:
{$MODE OBJFPC}
{$MODESWITCH ADVANCEDRECORDS}
program generic_bug2;
type
generic TList<T> = record
x : T;
end;
TA = specialize TList<Single>;
TB = specialize TList<Single>;
type TAHelper = record helper for TA
procedure Write;
end;
procedure TAHelper.Write;
begin
Write('A');
end;
type TBHelper = record helper for TB
procedure Write;
end;
procedure TBHelper.Write;
begin
Write('B');
end;
var A : TA;
B : TB;
begin
A.Write;
B.Write;
end.
So the above program outputs "AA" -- because type TA and TB are the
same. However, if we split out the generic and TA into another unit:
// Unit
{$MODE OBJFPC}
{$MODESWITCH ADVANCEDRECORDS}
unit generic_bug3_unit;
interface
type generic TList<T> = record
x : T;
end;
type TA = specialize TList<Single>;
type TAHelper = record helper for TA
procedure Write;
end;
implementation
procedure TAHelper.Write;
begin
Writeln('A');
end;
end.
// Program
{$MODE OBJFPC}
{$MODESWITCH ADVANCEDRECORDS}
program generic_bug3;
uses generic_bug3_unit;
type
TB = specialize TList<Single>;
type TBHelper = record helper for TB
procedure Write;
end;
procedure TBHelper.Write;
begin
Writeln('B');
end;
var
A : TA;
B : TB;
begin
A.Write;
B.Write;
end.
... then TA and TB are treated as separate types, hence each has it's
own helper -- program outputs "AB".
This is interesting. In my opinion (under the aspect that TA = TB
currently) it should print "BB" in both cases. I'll need to investigate
this.
Also the case that both spezializations in the same unit are treated the
same, but aren't in the other one. Also something I'll need to
investigate (also in FPC 2.7.1).
2) In the second program, is it OK that the compiler silently discards
the first Helper class, or maybe should it produce an error? Note that
this also works for non-generic records (what does Delphi do?)
As I said above: given that TA is considered equal to TB it should print
the same letter in both cases.
3) (most important for me) this all was discovered because I wanted to
find a way to have two different "flavors" of a base record, extended
by different helpers (eg. Vector4D base class extended to a
Quaternion, and a Color) -- using generics provided a easy way to make
a base record "evolve" into two distinct types, so in one unit I have
TGLColor4 = specialize TVector4< Single>; with a TGGColor4Helper and
in another I have TQuaternion = specialize TVector4<Single> with a
TQuaternionHelper). I really like this solution, but depending on the
way the above may change, I don't know if it won't be "fixed" not to
work anymore in a later version of FPC?
Currently they will sometimes be the same and sometimes not. This would
be ok if we wouldn't have helpers, but as we have helpers now as well a
solution for this needs to be found.
Regards,
Sven
_______________________________________________
fpc-devel maillist - fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel