Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread denisgolovan via fpc-pascal


> If you want to pass a pointer to ^T in a generic function is there anyway 
> safe to do this currently? Pascal doesn’t allow ^ types in function arguments 
> (why?) and generics don’t seems to support pointers either (why?).
> 
> generic TValues = array[0..0] of T;
> generic PValues = ^specialize TValues;
> 
> I guess the only thing to do is use a untyped pointer and cast it to the 
> correct type inside the function declaration?
> 
> For example here is a generic QuickSort function which operates on any array 
> of T.
> 
> type
> generic TComparator = function (left: T; right: T; context: pointer): 
> integer;
> 
> generic procedure QuickSort(_values: pointer; first, last: LongInt; 
> comparator: specialize TComparator);
> type
> TValues = array[0..0] of T;
> PValues = ^TValues;
> var
> pivot,j,i: integer;
> temp: T;
> values: PValues absolute _values;
> 
> Regards,
> Ryan Joseph
> 

Not that pretty, but I use something like:

==
generic TPtr = record
public
  type P = ^T;
public
  ptr: P;
  end;

generic function Ref(out r: specialize TPtr.P):boolean;
==

Denis Golovan
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Rainer Stratmann via fpc-pascal
Am Mittwoch, 20. April 2022, 19:15:15 CEST schrieb Sven Barth via fpc-pascal:
> This feature is enabled with the modeswitch
> ImplicitFunctionSpecialization and is for now not enabled by default as
> this has the potential to break existing code.

How many percent of the users need this feature?
Is it a feature that is a must?
Can everyone get also a solution without the feature?
Does it justify the risk of the whole language (has the potential to break 
existing code)?



___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Hairy Pixels via fpc-pascal


> On Apr 22, 2022, at 8:48 PM, Rainer Stratmann via fpc-pascal 
>  wrote:
> 
> How many percent of the users need this feature?
> Is it a feature that is a must?
> Can everyone get also a solution without the feature?
> Does it justify the risk of the whole language (has the potential to break 
> existing code)?

It’s like everything else in programming languages.

1) you can specialize the function manually so implicit specialization is not 
needed.
2) you can duplicate functions and change types manually so generic functions 
are not needed.
3) you can program in assembly so high-level languages are needed.
4) etc… :)

Joking aside it just makes for less code and more readable code (in my opinion).

Regards,
Ryan Joseph

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Rainer Stratmann via fpc-pascal
Am Freitag, 22. April 2022, 17:27:33 CEST schrieb Hairy Pixels via fpc-pascal:
> > On Apr 22, 2022, at 8:48 PM, Rainer Stratmann via fpc-pascal

> It’s like everything else in programming languages.
> 
> 1) you can specialize the function manually so implicit specialization is
> not needed. 
> 2) you can duplicate functions and change types manually so
> generic functions are not needed. 
> 3) you can program in assembly so high-level languages are needed. 
> 4) etc… :)
> 
> Joking aside it just makes for less code and more readable code (in my
> opinion).

From assembly to high-level language there is a huge step.
From high-level language to implicit generic function specializations it is a 
little step regarding the benefits.

In my opinion it makes everything more complicated. My mind refuses to read 
the description of the new feature.

But mostly I am worried because of the statement "has the potential to break 
existing code".
 


___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Howard Page-Clark via fpc-pascal

On 22/04/2022 17:13, Rainer Stratmann via fpc-pascal wrote:

Am Freitag, 22. April 2022, 17:27:33 CEST schrieb Hairy Pixels via fpc-pascal:

On Apr 22, 2022, at 8:48 PM, Rainer Stratmann via fpc-pascal

From assembly to high-level language there is a huge step.
 From high-level language to implicit generic function specializations it is a
little step regarding the benefits.

In my opinion it makes everything more complicated. My mind refuses to read
the description of the new feature.

But mostly I am worried because of the statement "has the potential to break
existing code".

Rainer,

We assume this is a language feature you will not use in your code, 
which is fine.


However, it is a cause for celebration among those who do welcome such 
syntax sugar, and will be using the feature to improve the size and 
readability of their code.


kind regards,

Howard

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Sven Barth via fpc-pascal

Am 22.04.2022 um 15:48 schrieb Rainer Stratmann via fpc-pascal:

Am Mittwoch, 20. April 2022, 19:15:15 CEST schrieb Sven Barth via fpc-pascal:

This feature is enabled with the modeswitch
ImplicitFunctionSpecialization and is for now not enabled by default as
this has the potential to break existing code.

How many percent of the users need this feature?


We don't deal in percentages, however it reduces the amount of typing 
required to write code with a lot of specializations (in theory an IDE 
like Lazarus *could* help here as well however).



Is it a feature that is a must?


It's only syntactic sugar, so *normally* a feature as this wouldn't be 
really be given much of a thought, however Delphi supports it as well.



Can everyone get also a solution without the feature?


Yes, by simply doing the specializations as usual (e.g. "specialize 
Add('Hello', 'World')" instead of "Add('Hello', 'World')"). As 
said, this is pure syntactic sugar.


Please note however that sometimes we also introduce features that you 
can't workaround that will also require changes to code if that feature 
in question is used (mainly by enabling the modeswitch). The RTTI 
attributes come to mind, cause then the directive clause for function 
directives can no longer be used if you want to use them:


=== code begin ===

{$mode objfpc}
{$modeswitch prefixedattributes}

function Foobar: LongInt; [stdcall, inline]; // this part is invalid
//function Foobar: LongInt; stdcall; inline; // and needs to be written 
like this

begin
end;

begin
end.

=== code end ===


Does it justify the risk of the whole language (has the potential to break
existing code)?


That is why it's behind a modeswitch and not enabled by default, so that 
it's in control of the user whether they want this or not. The problem 
space is rather small, but it nevertheless exists: you need to have a 
normal routine overloaded with a generic routine (for example across 
different units) and the compiler must decide to do an implicit 
specialization instead  of using the non generic routine (as it does 
without the feature enabled / before the feature was implemented), but 
the specialization of that function then needs to fail, because the 
generic routine can't be used with the type the compiler picked


Regards,
Sven
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Martin Frb via fpc-pascal

On 20/04/2022 19:15, Sven Barth via fpc-pascal wrote:
This feature allows you to use generic routines (functions, 
procedures, methods) without explicitely specializing them (“<…>” in 
Delphi modes and “specialize …<…>” in non-Delphi modes) as long as the 
compiler can determine the correct parameter types for the generic.


This feature is enabled with the modeswitch 
ImplicitFunctionSpecialization and is for now not enabled by default 
as this has the potential to break existing code.




One more step by Delphi to remove type safety.
IMHO a good option would have been to allow specializing multiple 
overloads in a single statement. But since Embarcadero has decided 
otherwise


I did explore what happens if I throw different types at it, and see how 
the current implementation deals with this (what I call) lack of type 
safety.
And also asked the question, how should it act?  (Because the current 
behaviour is new, expected to need fixes, and can obviously be fixed).



Assume you have the following function:
  generic function Add(aArg1, aArg2: T): T;
...

Up to now you could only use this function as follows:

SomeStr := specialize Add('Hello', 'World');
SomeInt := specialize Add(2, 5);

However with implicit function specializations enabled you can also 
use it as follows:


SomeStr := Add('Hello', 'World');
SomeInt := Add(2, 5);


So what happens if:

var
  b: Byte;
  c: Cardinal;
begin
  Add(b, c);

Well, I tested: It uses the type of the first Param. So it calls a 
function for both param of type Byte. The cardinal argument is 
converted. (potentially truncated).


If you use numeric constants:
  writeln('   0', Add(0, 0) );  // ShortInt
  writeln('1000', Add(1000, 1000) );  // SmallInt
  writeln('100K', Add(10, 10) );  // Integer

So then, if you try to fix   " Add(b, c)" by checking that b and c have 
the same type => "Add(c, 0)" will fail => because 0 is ShortInt and not 
cardinal.




I created a little test program (see bottom of mail).

And it gives a strange warning:

Compile Project, Target: 
C:\Users\martin\AppData\Local\Temp\project1.exe: Success, Warnings: 1, 
Hints: 3
project1.lpr(67,52) Warning: Range check error while evaluating 
constants (10 must be between -128 and 127)

project1.lpr(41,18) Hint: Local proc "Add$1" is not used
72 lines compiled, 0.2 sec, 105136 bytes code, 5476 bytes data

Line 41 is the declaration of the generic
   generic function Add(aArg1, aArg2: T): T;

So why does it generate "Add$1" if it does not use it? (Or rather why 
does it warn, if this is some internal details?)



And if you add to the app (at the top)

function Add(aArg1, aArg2: Int64): Int64; overload;
begin
//  write(' Int64 overload ');
  Result := aArg1 + aArg2;
end;

Then the line  (Shortint, because the first param is ShortInt)
 writeln(' 1,CK = ',Add(0, 10) ); // ShortInt

Will no longer call the specialized function, but instead use the int64 
version.


If you comment all "Add(...)" calls, except that one
=> Then you get an additional hint: "project1.lpr(81,41) Hint: Local 
proc "Add$1$crc9AB0BCED" is not used"
So then that very line generates a specialized version for the call, and 
then the compiler does not use it.



Yet if INSTEAD of adding the hardcoded Int64 variant (as given above), I 
let the compile create a Int64 version by adding

    writeln(' 1,CK = ',Add(int64(0), 10) ); // ShortInt
before the line above... Well the line above will not use that int64 
version, but use its own specialization...




program Project1;
{$mode objfpc}
{$ModeSwitch ImplicitFunctionSpecialization }
{//$H+}

uses SysUtils;

Procedure Foo(a: Integer; out r: ShortInt);
begin
  write(' ShortInt ');
  r := a;
end;
Procedure Foo(a: Integer; out r: SmallInt);
begin
  write(' SmallInt ');
  r := a;
end;
Procedure Foo(a: Integer; out r: Byte);
begin
  write(' Byte ');
  r := a;
end;
Procedure Foo(a: Integer; out r: Word);
begin
  write(' Word ');
  r := a;
end;
Procedure Foo(a: Integer; out r: Cardinal);
begin
  write(' Cardinal ');
  r := a;
end;
Procedure Foo(a: Integer; out r: Integer);
begin
  write(' Integer ');
  r := a;
end;
Procedure Foo(a: Integer; out r: Int64);
begin
  write(' Int64 ');
  r := a;
end;
Procedure Foo(a: Integer; out r: AnsiString);
begin
  write(' Ansi ');
  r := ' _A:'+IntToStr(a);
end;
Procedure Foo(a: Integer; out r: ShortString);
begin
  write(' Short ');
  r := ' _S:'+IntToStr(a);
end;

generic function Add(aArg1, aArg2: T): T;
var x: T;
begin
  Foo(SizeOf(T), x);
  {$R-}
  Result := aArg1 + aArg2 + x;
end;

var
  b: byte;
  c: cardinal;
begin
  b := 0;
  c := 0;

  writeln('    B = ',Add(b, b) );
  writeln('    C = ',Add(c, c) );
  writeln('    0 = ',Add(0, 0) );  // ShortInt
  writeln(' 1000 = ',Add(1000, 1000) );  // SmallInt
  writeln(' 100K = ',Add(10, 10) ); // Integer

  writeln;
  writeln('  c,b = ',Add(c, b) ); // Cardinal
  writeln('  

Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Mattias Gaertner via fpc-pascal
On Fri, 22 Apr 2022 20:51:56 +0200
Martin Frb via fpc-pascal  wrote:

>[...]
> I did explore what happens if I throw different types at it, and see
> how the current implementation deals with this (what I call) lack of
> type safety.
> And also asked the question, how should it act?  (Because the current 
> behaviour is new, expected to need fixes, and can obviously be fixed).

See Sven's first mail. 

 
>[...]
> So what happens if:
> 
> var
>    b: Byte;
>    c: Cardinal;
> begin
>    Add(b, c);
> 
> Well, I tested: It uses the type of the first Param. So it calls a 
> function for both param of type Byte. The cardinal argument is 
> converted. (potentially truncated).

Yes, as explained by Sven.

 
> If you use numeric constants:
>    writeln('   0', Add(0, 0) );  // ShortInt
>    writeln('1000', Add(1000, 1000) );  // SmallInt
>    writeln('100K', Add(10, 10) );  // Integer
> 
> So then, if you try to fix   " Add(b, c)" by checking that b and c
> have the same type => "Add(c, 0)" will fail => because 0 is ShortInt
> and not cardinal.

Why is that a fail?

 
> 
> I created a little test program (see bottom of mail).
> 
> And it gives a strange warning:
> 
> Compile Project, Target: 
> C:\Users\martin\AppData\Local\Temp\project1.exe: Success, Warnings:
> 1, Hints: 3
> project1.lpr(67,52) Warning: Range check error while evaluating 
> constants (10 must be between -128 and 127)

Add(0, 10)
Correct range error.


> project1.lpr(41,18) Hint: Local proc "Add$1" is not used
> 72 lines compiled, 0.2 sec, 105136 bytes code, 5476 bytes data
> Line 41 is the declaration of the generic
>     generic function Add(aArg1, aArg2: T): T;

Maybe related to
https://gitlab.com/freepascal.org/fpc/source/-/issues/39675


>[...]

Mattias
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Mattias Gaertner via fpc-pascal
On Fri, 22 Apr 2022 20:51:56 +0200
Martin Frb via fpc-pascal  wrote:

>[...]
> Well, I tested: It uses the type of the first Param. So it calls a 
> function for both param of type Byte. The cardinal argument is 
> converted. (potentially truncated).

I agree that Delphi should have used a better algorithm, like checking
the var/out arguments first and otherwise use the smallest
integer that fits all related params. Same for strings and boolean.
pas2js uses a similar algorithm. 

In $mode Delphi fpc must use the Delphi algorithm. In other modes it
could use a better algorithm.
If fpc would use the above algorithm in mode objfpc, the Add would work
like FPC's add:

generic function Add(a,b: T): T;
begin
  Result:=a+b;
end;

Add(aByte,aCardinal) -> cardinal


And you don't need to put a var/out param leftmost:

generic procedure Adding(a,b: T; out c: T);
begin
  c:=a+b;
end;

Adding(3,4,aWord);


Mattias

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Rainer Stratmann via fpc-pascal
Am Freitag, 22. April 2022, 19:53:34 CEST schrieben Sie:
> Am 22.04.2022 um 15:48 schrieb Rainer Stratmann via fpc-pascal:
> > Am Mittwoch, 20. April 2022, 19:15:15 CEST schrieb Sven Barth via fpc-
pascal:

> We don't deal in percentages, however it reduces the amount of typing
> required to write code with a lot of specializations (in theory an IDE
> like Lazarus *could* help here as well however).

Of course 'you' do. When I asked for a simple feature years ago it was 
refused. And there were several explanations why this feature is not 
necessary.


___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Sven Barth via fpc-pascal

Am 22.04.2022 um 20:51 schrieb Martin Frb via fpc-pascal:

I created a little test program (see bottom of mail).

And it gives a strange warning:

Compile Project, Target: 
C:\Users\martin\AppData\Local\Temp\project1.exe: Success, Warnings: 1, 
Hints: 3
project1.lpr(67,52) Warning: Range check error while evaluating 
constants (10 must be between -128 and 127)

project1.lpr(41,18) Hint: Local proc "Add$1" is not used
72 lines compiled, 0.2 sec, 105136 bytes code, 5476 bytes data

Line 41 is the declaration of the generic
   generic function Add(aArg1, aArg2: T): T;

So why does it generate "Add$1" if it does not use it? (Or rather why 
does it warn, if this is some internal details?)


Add$1 is the symbol of the generic itself, *not* the specialization. But 
please report it, cause that definitely shouldn't be the case anyway, as 
the generic is after all used by the specializations (and I should 
compile with -vh more often...)





And if you add to the app (at the top)

function Add(aArg1, aArg2: Int64): Int64; overload;
begin
//  write(' Int64 overload ');
  Result := aArg1 + aArg2;
end;

Then the line  (Shortint, because the first param is ShortInt)
 writeln(' 1,CK = ',Add(0, 10) ); // ShortInt

Will no longer call the specialized function, but instead use the 
int64 version.


Correct, because a matching non-generic variant is available and the 
compiler then picks that.




If you comment all "Add(...)" calls, except that one
=> Then you get an additional hint: "project1.lpr(81,41) Hint: Local 
proc "Add$1$crc9AB0BCED" is not used"
So then that very line generates a specialized version for the call, 
and then the compiler does not use it.


The compiler essentially works like this: it generates a suitable set of 
overloads. This includes the non-generic routines as well as all generic 
routines for which suitable type parameters can be found. Out of this 
set the compiler will then pick the function it will finally use with a 
preference for non-generic functions (even if parameters might be a 
worse, though not incompatible match).


That said: if the compiler does not pick one of the specializations it 
should totally discard them, so please report a bug for this as well.





Yet if INSTEAD of adding the hardcoded Int64 variant (as given above), 
I let the compile create a Int64 version by adding

    writeln(' 1,CK = ',Add(int64(0), 10) ); // ShortInt
before the line above... Well the line above will not use that int64 
version, but use its own specialization...


The compiler determines the generic type parameters for each call. In 
this case it will be Int64 due to the typecast. However that will not 
change what the other, previous Add calls use and it also won't affect 
one any following Add call, cause it will simply determine the set of 
elligible functions (and other implicit specializations as well as 
explicit specializaitons are *not* part of this) and then determine 
which one to call out of this set (the compiler might specialize the 
same generic function with the same generic type parameters multiple 
times then, but the part that's dealing with specializations in general 
will detect that and point to the existing symbol instead).


Regards,
Sven
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Sven Barth via fpc-pascal

Am 22.04.2022 um 22:22 schrieb Mattias Gaertner via fpc-pascal:

On Fri, 22 Apr 2022 20:51:56 +0200
Martin Frb via fpc-pascal  wrote:


[...]
Well, I tested: It uses the type of the first Param. So it calls a
function for both param of type Byte. The cardinal argument is
converted. (potentially truncated).

I agree that Delphi should have used a better algorithm, like checking
the var/out arguments first and otherwise use the smallest
integer that fits all related params. Same for strings and boolean.
pas2js uses a similar algorithm.


Considering that we're talking mainly about differences of width and 
precision (e.g. the differences between a string and a record are more 
clear) this can probably be improved without considering Delphi here, 
because this is nowhere documented... (our non-generic overload 
selection might lead to different results after all as well) But even if 
we only improve this for non-Delphi modes I agree that a suggestion like 
yours would be an improvement.


Regards,
Sven
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Martin Frb via fpc-pascal

On 22/04/2022 23:12, Sven Barth via fpc-pascal wrote:

Am 22.04.2022 um 20:51 schrieb Martin Frb via fpc-pascal:



So why does it generate "Add$1" if it does not use it? (Or rather why 
does it warn, if this is some internal details?)


Add$1 is the symbol of the generic itself, *not* the specialization. 
But please report it, cause that definitely shouldn't be the case 
anyway, as the generic is after all used by the specializations (and I 
should compile with -vh more often...)


=> Then you get an additional hint: "project1.lpr(81,41) Hint: Local 
proc "Add$1$crc9AB0BCED" is not used"
So then that very line generates a specialized version for the call, 
and then the compiler does not use it.


The compiler essentially works like this: it generates a suitable set 
of overloads. This includes the non-generic routines as well as all 
generic routines for which suitable type parameters can be found. Out 
of this set the compiler will then pick the function it will finally 
use with a preference for non-generic functions (even if parameters 
might be a worse, though not incompatible match).


That said: if the compiler does not pick one of the specializations it 
should totally discard them, so please report a bug for this as well.


Done
https://gitlab.com/freepascal.org/fpc/source/-/issues/39684
https://gitlab.com/freepascal.org/fpc/source/-/issues/39685
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Martin Frb via fpc-pascal

Possible one more / Though more of an optimization.

If the code has multiple
    Add(Int64(0), Int64(0));
then they will all use the same procedure (just break in the debugger 
and check the CRC).


But if  one specialization is explicit and the other implicit then 2 
identical (as far as I can tell with -al ) functions (with diff CRC) are 
created.


There is however a subtle difference in the generate asm.
The explicit specialization has comment for the source code
# [6] begin
...
# [7] Result := aArg1 + aArg2;
...

The implicit does not have those.
Actually I checked that a bit deeper. The comment occur in (and only in) 
the first specialization (implicit or explicit).

All other specialization are without comments for the source.



program Project1;
{$mode objfpc}
{$ModeSwitch ImplicitFunctionSpecialization }

generic function Add(aArg1, aArg2: T): T;
begin
  Result := aArg1 + aArg2;
end;

begin
  specialize Add(Int64(0), Int64(0));  // No Hint
  Add(Int64(0), Int64(0));
end.


___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Feature announcement: implicit generic function specializations

2022-04-22 Thread Hairy Pixels via fpc-pascal


> On Apr 23, 2022, at 5:18 AM, Martin Frb via fpc-pascal 
>  wrote:
> 
> Done
> https://gitlab.com/freepascal.org/fpc/source/-/issues/39684
> https://gitlab.com/freepascal.org/fpc/source/-/issues/39685

It looks like I need to do some cleanup phase. I can’t remember how it works 
right now but I think I made the specialization so that it could be considered 
in overloading but after it was used it needs to be marked so hints aren’t 
given or deleted entirely (probably at the end of the unit if there is someway 
to know it was never used). Sven may have some ideas on how this works so feel 
free to drop them in the Gitlab issue.

Regards,
Ryan Joseph

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal