Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2025-07

generic constraints...

6 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

Currently you can't do

type
   generic TFoo<A> = class
      procedure Bar; virtual;
   end;
   generic FooChild<F: TFoo> = class(F)
      procedure Bar; override;
   end;

However, without giving the TFoo you can't do the "Bar; override", because it wont know that the base class has a virtual Bar method.

In many case you can make the first class non generic. But if you have several generics like that and they all take base classes as generic param, in order to then do something like TFinal = class(
   specialize TBase1<
     specialize TBase2<
         specialize TBase3<TSomething>
     >
   >
)
end;

Then they all must be generics....
So in that case it would be nice to allow the generic as constraint.

---------------------------

On a related note, if building classes like that, there is another problem...

   generic TClassExtender<B: class> = class(B)
      constructor Create; // override
      // same for other methods
   end;
    constructor TClassExtender.Create;
    begin
      inherited;
      MyInit;
   end;

the  base class used in specialization may have a constructor that takes arguments....
Then you can't override/reintroduce those, because you don't yet know all the base classes.

It would be nice to have something (idea wise / not syntax wise)   generic TClassExtender<B: class> = class(B)
     generic override constructor Create; // override      // same for other methods
  end;

That would create the same constructor for each version the base class has.
- call the correct inherited
- have the same code around the inherit

Not sure if this should be limited for virtual/override / or be for any method.
(same for ordinary methods)

Reply by email

Mattias Gaertner
to Martin Frb
Martin Frb wrote 10 lines
Currently you can't do type   generic TFoo<A> = class      procedure Bar; virtual;   end;   generic FooChild<F: TFoo> = class(F)      procedure Bar; override;   end;

Can you use:

    generic FooChild<T> = class(specialize TFoo<T>)
       procedure Bar; override;
    end;
?

Mattias

Reply by email

Martin Frb
to Mattias Gaertner
Mattias Gaertner wrote 20 lines
On 7/25/25 13:44, Martin Frb via fpc-devel wrote: > Currently you can't do > > type >    generic TFoo<A> = class >       procedure Bar; virtual; >    end; > >    generic FooChild<F: TFoo> = class(F) >       procedure Bar; override; >    end; Can you use:    generic FooChild<T> = class(specialize TFoo<T>)       procedure Bar; override;    end; ?

No.

One example is that I have several
  TItem1, TItem2, TItem3,...
and for each a
    TItem1List = specialize TFpgList<TItem1>;

But I don't actually use TItem1, ....

I use
  TMyFinalItem1 =
       specialize TFeatureX<
           specialize TFeatureY<
               specialize TFeatureZ< TItem1 >           >
      >;

And each list needs to be
  TMyFinalItem1 =
       specialize TFeatureXForList<
           specialize TFeatureYForList<
               specialize TFeatureZForList< specialize TFpgList<TItem1>   >           >
      >;

Currently I can swap the order, and git it working by creating a non generic base.... But that introduces dependencies that were not wanted...

Also, the error by the compiler is
     Error: Generics without specialization cannot be used as a type for a variable

But
   generic FooChild<F: TFoo> = class(F)

- F is not a variable
- TFoo in not a type (for somethnig), TFoo is a constraint

If that syntax was allowed, it should mean that
-  F must be of any type that is (a descendand of) a specialization of TFoo.

So this is NOT to allow FooChild to be specialized with another generic, but with a (any) specialization of that generic.

Reply by email

Mattias Gaertner
to Martin Frb
Martin Frb wrote 41 lines
On 25/07/2025 15:20, Mattias Gaertner via fpc-devel wrote: > > > On 7/25/25 13:44, Martin Frb via fpc-devel wrote: >> Currently you can't do >> >> type >>    generic TFoo<A> = class >>       procedure Bar; virtual; >>    end; >> >>    generic FooChild<F: TFoo> = class(F) >>       procedure Bar; override; >>    end; [...] No. One example is that I have several   TItem1, TItem2, TItem3,... and for each a     TItem1List = specialize TFpgList<TItem1>; But I don't actually use TItem1, .... I use   TMyFinalItem1 =        specialize TFeatureX<            specialize TFeatureY<                specialize TFeatureZ< TItem1 >           >       >; And each list needs to be   TMyFinalItem1 =        specialize TFeatureXForList<            specialize TFeatureYForList<                specialize TFeatureZForList< specialize TFpgList<TItem1>   >           >       >;

IMO that does not look human friendly for reading and debugging.

Show quoted text 13 lines
Currently I can swap the order, and git it working by creating a non generic base.... But that introduces dependencies that were not wanted... Also, the error by the compiler is      Error: Generics without specialization cannot be used as a type for a variable But    generic FooChild<F: TFoo> = class(F) - F is not a variable - TFoo in not a type (for somethnig), TFoo is a constraint

The problem is the ambiguity of TFoo, because Delphi (aka modeswitch) distinguishes TFoo, TFoo and TFoo<,>:

type
   generic TFoo<A> = class
      procedure Bar; virtual;
   end;
   generic TFoo<A,B> = class
      procedure NoBar; virtual;
   end;
   generic FooChild<F: TFoo> = class(F)
      procedure Bar; override;
   end;

So you have to be more specific:

   generic FooChild<A,F: specialized TFoo<A>> = class(F)
      procedure Bar; override;
   end;
Show quoted text 6 lines
If that syntax was allowed, it should mean that -  F must be of any type that is (a descendand of) a specialization of TFoo. So this is NOT to allow FooChild to be specialized with another generic, but with a (any) specialization of that generic.

AFAIK there is currently no "Any" placeholder in constraints. It would be something like
generic FooChild<F: specialized TFoo> = ...

Although that looks like something was forgotten. Maybe better:

generic FooChild<F: specialized TFoo<*>> = ...

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 11 lines
> > And each list needs to be >   TMyFinalItem1 = >        specialize TFeatureXForList< >            specialize TFeatureYForList< >                specialize TFeatureZForList< specialize TFpgList<TItem1> >   > >           > >       >; IMO that does not look human friendly for reading and debugging.

Let's hope it was a contrived example :-)

Show quoted text 52 lines
> Currently I can swap the order, and git it working by creating a non > generic base.... But that introduces dependencies that were not wanted... > > > Also, the error by the compiler is >      Error: Generics without specialization cannot be used as a type > for a variable > > But >    generic FooChild<F: TFoo> = class(F) > > - F is not a variable > - TFoo in not a type (for somethnig), TFoo is a constraint The problem is the ambiguity of TFoo, because Delphi (aka modeswitch) distinguishes TFoo, TFoo and TFoo<,>: type generic TFoo<A> = class procedure Bar; virtual; end; generic TFoo<A,B> = class procedure NoBar; virtual; end; generic FooChild<F: TFoo> = class(F) procedure Bar; override; end; So you have to be more specific: generic FooChild<A,F: specialized TFoo<A>> = class(F) procedure Bar; override; end; > If that syntax was allowed, it should mean that > -  F must be of any type that is (a descendand of) a specialization of > TFoo. > > So this is NOT to allow FooChild to be specialized with another generic, > but with a (any) specialization of that generic. AFAIK there is currently no "Any" placeholder in constraints. It would be something like generic FooChild<F: specialized TFoo> = ... Although that looks like something was forgotten. Maybe better: generic FooChild<F: specialized TFoo<*>> = ...

it seems to me that 'specialized' is not compatible with 'any', as specialized needs a specific type: it actually creates the type.

So that would need to become something like
generic FooChild<F: TFoo<*>> = ..

Michael.

Reply by email

Martin Frb
to Mattias Gaertner: IMO that does not look human friendly for reading and debugging. The problem is the…
Mattias Gaertner wrote 11 lines
On 7/25/25 16:31, Martin Frb via fpc-devel wrote: > > But >     generic FooChild<F: TFoo> = class(F) > > - F is not a variable > - TFoo in not a type (for somethnig), TFoo is a constraint The problem is the ambiguity of TFoo, because Delphi (aka modeswitch) distinguishes TFoo, TFoo and TFoo<,>:

Ok, yes. If ever a generic parameter can refer to an (non specialized) generic

     generic Foo<G: TGeneric> = class
       type TSome = G<F> ;

Then the name of the generic can not be used as "any specialized type of that generic"

Unless it then needs to be prefixed
    generic Foo<G: generic TGeneric> = class

And/or less constrained
    generic Foo<G: generic> = class

Show quoted text 8 lines
AFAIK there is currently no "Any" placeholder in constraints. It would be something like   generic FooChild<F: specialized TFoo> = ... Although that looks like something was forgotten. Maybe better:   generic FooChild<F: specialized TFoo<*>> = ...

Would be nice to have.
It also needs the placeholders to be able to distinguish   generic TBar<A>
  generic TBar<A,B>

  generic FooChild<F: specialize TBar<,>) = ...
  generic FooChild<F: TBar<,>) = ...

not sure if it should really say "specialize" (even in objfpc) because it isn't doing it, it is expecting it to be done elsewhere.

@FPC Team: Worth a feature request?

Reply by email