[fpc-devel] Additional generic type constraints
Kostas Michalopoulos
badsectoracula at gmail.com
Thu Feb 23 17:59:14 CET 2023
On 2/22/23 15:11, Sven Barth wrote:
> Kostas Michalopoulos via fpc-devel <fpc-devel at lists.freepascal.org
> <mailto:fpc-devel at lists.freepascal.org>> schrieb am Mi., 22. Feb. 2023,
> 10:37:
>
> > Because Delphi doesn't have them and when constraints were
> implemented
> > they were implemented for Delphi compatibility.
>
> Can they be added? The original announcement ~13 years ago mentioned
> that those could be added at some point. "object" and "operator X"
> would
> be quite useful for me.
>
>
> Some additional constraints might be added. However I have none of them
> planned currently and enough other things to do.
>
>
> I tried to use constraints at some point in my code but they proven too
> limited in functionality - the biggest issue i faced was that i
> couldn't
> use a specialization with a forward declared class (which is the entire
> point of the forward declaration). For example i have a generic
> collection that only works on TSerializable subclasses so i gave it
> that
> constraint, but in another unit i need to define a specialization
> for it
> before it was defined (so the class was available with a forward class
> declaration) since that specialization also needs to be used by the
> class itself. In general it seems like having constrained generic work
> with a tree structure of derived types that use the generic itself is
> impossible.
>
> Wouldn't storing a list of "specializations to confirm later in this
> unit" work (with later being when the class is actually defined in the
> unit)? The language already has forward declarations for a bunch of
> other things.
>
>
> Forward declarations can not be used for constraints, because a
> specialization of the generic might be used before the forward declared
> type is fully defined and the compiler *must* be able to check whether
> the parameter in question is compatible at the time the specialization
> is declared.
>
> Regards,
> Sven
>
That is what the compiler does now, but can't it be changed to treat
constraints that use forward declarations as unconstrained (at least as
far as these forward declarations are concerned) until the moment they
are declared and validate those constraints at that point?
After all the code below does work if there is no constraint despite the
specialization being used before the forward declaration:
----
program Test;
{$MODE OBJFPC}{$H+}
type
TProvidesFoo = class
function Foo: Integer; virtual; abstract;
end;
// The following with a constraint could be instead:
// generic TGetFoo<T: TProvidesFoo> = class
generic TGetFoo<T> = class
Wrap: T;
function GetFoo: Integer;
end;
type
TForwardClass = class;
// Instead of making the test here, add it to a list to check later...
TFCHasFoo = specialize TGetFoo<TForwardClass>;
procedure DumpFoo(FCHasFoo: TFCHasFoo);
begin
Writeln(FCHasFoo.GetFoo);
end;
function TGetFoo.GetFoo: Integer;
begin
Result:=Wrap.Foo;
end;
type
// ...and when this is declared check the if any of the remaining
// checks in the list will be valid or not and remove it from the list
TForwardClass = class(TProvidesFoo)
function Foo: Integer; override;
end;
function TForwardClass.Foo: Integer;
begin
Result:=42;
end;
var
FC: TForwardClass;
HF: TFCHasFoo;
begin
HF:=TFCHasFoo.Create;
HF.Wrap:=TForwardClass.Create;
DumpFoo(HF);
HF.Wrap.Free;
HF.Free;
end.
----
At the end of the day this isn't a major flaw, after all if the expected
functionality wasn't there (e.g. the generic code tried to access
something the type used in the specialization didn't provide) you'd
still get a compile error anyway, though it does feel a bit like there a
hole in Free Pascal's type safety here (e.g. imagine passing a type to a
specialization that happens to have the same function call so the code
compiles but the call does something different than what you'd expect).
Kostas
More information about the fpc-devel
mailing list