[fpc-devel] New feature announcement: constant parameters for generics

Sven Barth pascaldragon at googlemail.com
Sun Apr 26 11:48:59 CEST 2020

Am 26.04.2020 um 09:38 schrieb Michael Van Canneyt:
> On Sun, 26 Apr 2020, Ryan Joseph via fpc-devel wrote:
>>> On Apr 26, 2020, at 5:13 AM, Sven Barth via fpc-devel 
>>> <fpc-devel at lists.freepascal.org> wrote:
>>> The Free Pascal team is happy to announce the addition of a new 
>>> language feature: constant parameters for generics.
>> Excellent! Thanks for getting this merged. It was a long battle but 
>> it's finally over. ;)
> As the original author, can you say something about the intended use 
> of this feature ?
> Sven gave some examples, and they show how it works, but from his 
> examples I don't see the point
> of this feature.

Jeppe had provided a potential usecase on the core mailing list in 
October '18. His example is not useable as-is, but to give you an idea:

=== code begin ===

program tgpio;

{$mode objfpc}
{$modeswitch advancedrecords}

  generic TSomeMicroGPIO<const Base: PtrUInt> = record
    procedure SetPin(aIndex: SizeInt; aEnable: Boolean); inline;
    function GetPin(aIndex: SizeInt): Boolean; inline;
    property Pin[Index: SizeInt]: Boolean read GetPin write SetPin;

procedure TSomeMicroGPIO.SetPin(aIndex: SizeInt; aEnable: Boolean);
   if aEnable then
     PLongWord(Base)[2] := PLongWord(Base)[2] or (1 shl aIndex)
     PLongWord(Base)[2] := PLongWord(Base)[2] and not (1 shl aIndex);

function TSomeMicroGPIO.GetPin(aIndex: SizeInt): Boolean;
   Result := (PLongWord(Base)[2] and (1 shl aIndex)) <> 0

   GPIOA: specialize TSomeMicroGPIO<$8000F000>;
   GPIOB: specialize TSomeMicroGPIO<$8000F100>;
   GPIOC: specialize TSomeMicroGPIO<$8000F200>;

   GPIOA.Pin[2] := True;

=== code end ===

As the compiler can inline all this, the writing of maintainable, 
hardware agnostic frameworks for embedded controllers becomes easier.

In general I agree with you that the use of constants as generic 
parameters is less wide. But there cases where one might want them.

A further example could be to determine the size of a hash table: 
Determining that at compile time instead of runtime might allow for 
better code. At the same time the user of that code would still be able 
to influence it.

In the bug report there was a further example by Akira1364. At its core 
it's about static arrays again, but it shows what can be done with this:

=== code begin ===

program ConstMatrixExampleObjFPC;

{$mode ObjFPC}
{$modeswitch AdvancedRecords}

   String3 = String[3];

   generic TRawMatrix<T; const N: SizeUInt> = array[0..N-1] of 
array[0..N-1] of T;

   generic TMatrix<T; const N: SizeUInt> = record
   private type
     ArrayType = specialize TRawMatrix<T, N>;
     Data: ArrayType;
     class operator :=(constref Arr: ArrayType): TMatrix; inline;
     procedure Display;

   class operator TMatrix.:=(constref Arr: ArrayType): TMatrix;
     Result.Data := Arr;

   procedure TMatrix.Display;
   var I, J: SizeInt;
     for I := 0 to N - 1 do begin
       Write(' [');
       for J := 0 to N - 2 do
         Write(Data[I, J], ', ');
       Write(Data[I, N - 1]);
       Writeln('] ');

const RawMat: specialize TRawMatrix<String3, 4> = (
   ('AAA', 'BBB', 'CCC', 'DDD'),
   ('EEE', 'FFF', 'GGG', 'HHH'),
   ('III', 'JJJ', 'KKK', 'LLL'),
   ('MMM', 'NNN', 'OOO', 'PPP')

var Mat: specialize TMatrix<String3, 4>;

   Mat := RawMat;

=== code end ===

I'm sure the future will show more potential examples. Or one could look 
at C++ examples that allow constants as well.


More information about the fpc-devel mailing list