Recent

Author Topic: Generic Parameter Passing  (Read 1162 times)

Warfley

  • Hero Member
  • *****
  • Posts: 1855
Generic Parameter Passing
« on: March 18, 2022, 11:16:42 pm »
So here is a weird thing I was wondering about quite a while. Taking a generic class:
Code: Pascal  [Select][+][-]
  1.   generic TTest<T, U> = class(TObject);
And you want to do a partial specialization, you can do the following:
Code: Pascal  [Select][+][-]
  1.   generic TOneGenericParamSubclass<T> = class(specialize TTwoGenericParams<T, Integer>);
But you can't do the following:
Code: Pascal  [Select][+][-]
  1.   generic TOneGenericParam<T> = specialize TTwoGenericParams<T, Integer>; // Error Identifier not found "T"

For classes this is annoying but nothing more as the subclass method can be used easiely, but for other types this is kinda a dealbreaker, e.g. for functions:
Code: Pascal  [Select][+][-]
  1.   generic TUnaryFunction<TResult, TParam> = function(const AValue: TParam): TResult;
  2.   generic TToStringFunction<TData> = specialize TUnaryFunction<String, TData>;
Or for records:
Code: Pascal  [Select][+][-]
  1.   generic TUnion<TFirst, TSecond> = record
  2.     // ...
  3.   end;
  4.   generic TUnaryFunctionRaw<TResult, TParam> = function(const AValue: TParam): TResult;
  5.   generic TUnaryFunctionMethod<TResult, TParam> = function(const AValue: TParam): TResult of object;
  6.  
  7.   generic TUnaryFunction<TResult, TParam> =
  8.     specialize TUnion<specialize TUnaryFunctionRaw<TResult, TParam>,
  9.                       specialize TUnaryFunctionMethod<TResult, TParam>>;

This behavior is in the fpc for a long time now, so my question is, is this intentional or a bug? I found this to be really annoying as it makes a lot of things simply not possible. And I do not see a workaround for this
« Last Edit: March 18, 2022, 11:19:54 pm by Warfley »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5823
  • Compiler Developer
Re: Generic Parameter Passing
« Reply #1 on: March 19, 2022, 04:58:50 pm »
This behavior is in the fpc for a long time now, so my question is, is this intentional or a bug? I found this to be really annoying as it makes a lot of things simply not possible. And I do not see a workaround for this

FPC simply does not support the declaration of partial specializations (it implicitly supports them as you can see in the example where you descend a class from a partial specialization, but it provides no explicit way to use them).

Warfley

  • Hero Member
  • *****
  • Posts: 1855
Re: Generic Parameter Passing
« Reply #2 on: March 19, 2022, 06:58:33 pm »
So this is intendet?

This also means that type aliases are also not possible with FPC?
Code: Pascal  [Select][+][-]
  1.   generic TTest<T> = class(TObject);
  2.   generic TAlias1<T> = specialize TTest<T>;
  3.   generic TAlias2<T> = type specialize TTest<T>;
Or nested specializations:
Code: Pascal  [Select][+][-]
  1.   generic TFoo<T> = class(TObject);
  2.   generic TBar<T> = class(TObject);
  3.   generic TFooBar<T> = specialize TFoo<specialize TBar<T>>;

I have found out that it is possible by just adding another layer of indirection:
Code: Pascal  [Select][+][-]
  1.   generic TTest<T> = class(TObject);
  2.   generic TestAlias<T> = class public type
  3.   TTestAlias = specialize TTest<T>;
  4.   TTestAliasNewType = type specialize TTest<T>;
  5.   end;
  6.  
  7. // usage:
  8. var
  9.   t1: specialize TestAlias.TAlias1<Integer>;
  10.   t2: specialize TestAlias.TAlias2<Integer>;

Honestly, I find this is a rather odd choice, because type aliasing an essential part of Pascal and is required (especially when dealing with cross plattform code, just look at for example the sockets unit), so requiring programmers to use such workarounds forces them to write worse code

PascalDragon

  • Hero Member
  • *****
  • Posts: 5823
  • Compiler Developer
Re: Generic Parameter Passing
« Reply #3 on: March 20, 2022, 11:47:53 am »
So this is intendet?

I wouldn't say “intended”, but simply “not implemented”. The generics are a rather complex functionality in the compiler and there are many things that can go wrong when one changes something.

This also means that type aliases are also not possible with FPC?
Code: Pascal  [Select][+][-]
  1.   generic TTest<T> = class(TObject);
  2.   generic TAlias1<T> = specialize TTest<T>;
  3.   generic TAlias2<T> = type specialize TTest<T>;

Correct.

Or nested specializations:
Code: Pascal  [Select][+][-]
  1.   generic TFoo<T> = class(TObject);
  2.   generic TBar<T> = class(TObject);
  3.   generic TFooBar<T> = specialize TFoo<specialize TBar<T>>;

Nested specializations are supported, but not as part of a construct like that.

Honestly, I find this is a rather odd choice, because type aliasing an essential part of Pascal and is required (especially when dealing with cross plattform code, just look at for example the sockets unit), so requiring programmers to use such workarounds forces them to write worse code

This has nothing to do with “odd choice”, but simply with generics still being essentially “in development”. Many of the things that are possible today weren't possible with the original idea of generics (which were conceived before Delphi added theirs). If something turns out to be a useful functionality it will be implemented. The question is mainly when, cause as written above: generics are complex and prone to breakage and I have only so much time I can invest into working on FPC.

 

TinyPortal © 2005-2018