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

2022-05-01 Thread Hairy Pixels via fpc-pascal


> On May 1, 2022, at 10:36 AM, Hairy Pixels  wrote:
> 
> Not sure what the best solution is but here are the ones I can think of:
> 
> 1) allow the helpers to use “array/set of T” syntax.

Sorry for the noise, one last point on this. So it looks like type helpers are 
already so strictly typed that a type alias for a dynamic array is not 
compatible with the anonymous dynamic array type (see below). Can this 
restriction be lifted or is it intentional in the design? I would think that 
TIntArray is just an alias and thus should be functionally the same as “array 
of integer”.

type
  TIntArray = array of integer;
  TMyArrayHelper = type helper for TIntArray
procedure DoThis;
  end;

  procedure TMyArrayHelper.DoThis;
  begin
writeln(Length(self));
  end;

var
  a: array of integer;
begin
  a.DoThis; // Illegal qualifier:
end.

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-30 Thread Hairy Pixels via fpc-pascal


> On Apr 30, 2022, at 6:17 PM, Hairy Pixels  wrote:
> 
> 2) Right now helpers only support single types but they would need to be 
> extended to support “array of T”, “set of T”,which by, why aren’t those 
> supported as it is? I can’t seem to think of any reason they should be 
> disallowed. The alternative is using an auxiliary generic type which kind of 
> confounds things because then you’re extending a new type instead of the 
> underlying array of set type.

Looking at this problem this morning and I wanted to give an example of what I 
was talking about.

type
  generic TArray = array of T;
  generic TMyHelper = type helper for specialize TArray
  end;
  TIntHelper = specialize TMyHelper;

The problem is TIntHelper is going to extend the type TArray instead 
of “array of Integer” (not to mention the boiler plate) so extra steps would 
have to be taking to make sure “array of T” type can find the helpers for 
TArray. 

Not sure what the best solution is but here are the ones I can think of:

1) allow the helpers to use “array/set of T” syntax.
2) register helpers for both types.
3) perform an extra step to search helpers for “array of T” or “set of T” types.

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-30 Thread Flávio Etrusco via fpc-pascal
Hi,

Em sáb., 30 de abr. de 2022 às 09:13, Mattias Gaertner via fpc-pascal
 escreveu:
>
> AFAIK it is planned for mode objfpc to support distinguishing types via
> template count as in mode delphi:
>
> type
>   TMyClass = class
>   end;
>   generic TMyClass = class
>   end;
>   generic TMyClass = class
>   end;

This seems very likely to generate confusion, doesn`t it?


Best regards,
Flávio
___
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-30 Thread Hairy Pixels via fpc-pascal


> On Apr 30, 2022, at 7:02 PM, Mattias Gaertner via fpc-pascal 
>  wrote:
> 
> AFAIK it is planned for mode objfpc to support distinguishing types via
> template count as in mode delphi:
> 
> type
> TMyClass = class
> end;
> generic TMyClass = class
> end;
> generic TMyClass = class
> end;
> 
> So you would need something similar for helpers:
> 
> THelper = class helper for TMyClass
> end;
> generic THelper = class helper for specialize TMyClass 
> end;
> generic THelper = class helper for specialize TMyClass 
> end;

Now that would be a duplicate identifier error but that may be changed for 
Delphi compatibility? That indeed would break any possible shorthands. Maybe at 
least the specialize could be omitted because of the grammar which is so 
annoying. :)

To the extent I have a todo list I’ve had plans to make a mode switch for 
“generic keywords” so you could disable them in Object Pascal mode (Svens 
idea). That would fix the specialize problem but honestly I kind of like the 
generic keyword as it’s a prefix and makes the type more clear. It’s the 
specialize keyword I have a problem with.

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-30 Thread Mattias Gaertner via fpc-pascal
On Sat, 30 Apr 2022 18:17:25 +0700
Hairy Pixels via fpc-pascal  wrote:

>[...]
> So I wonder if the shorthand:
> 
>   generic THelper = class helper for TMyClass

AFAIK it is planned for mode objfpc to support distinguishing types via
template count as in mode delphi:

type
  TMyClass = class
  end;
  generic TMyClass = class
  end;
  generic TMyClass = class
  end;

So you would need something similar for helpers:

  THelper = class helper for TMyClass
  end;
  generic THelper = class helper for specialize TMyClass 
  end;
  generic THelper = class helper for specialize TMyClass 
  end;


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-30 Thread Hairy Pixels via fpc-pascal


> On Apr 25, 2022, at 8:27 PM, Hairy Pixels  wrote:
> 
>> For some reason I don't get all mails by Ryan, so I reply here:
>> 
>> Helpers currently can't be generic and even if they could be (which I do 
>> plan to add) it would require an explicit specialization of the helper to be 
>> used because the compiler will not be tasked with searching for potential 
>> generic helpers and then implicitly specializing a whole helper type with 
>> all its methods to maybe use it for an implicit specialization (and it needs 
>> to specialize the helper first to decide whether it even remotely contains 
>> suitable methods). 
>> 
> 
> You could do a search for method names and parameters to see if a generic 
> helper was a candidate before specialization. That would reduce the possible 
> space for needless specializations right? For non-object types this would be 
> even less intrusive since it would only be competing with other helper 
> methods.

Note: CC’ing Sven in case he’s not getting these.

First off see my reply above about implicit. Question is why can’t you filter 
out possible helpers by doing a pre-pass check for matching names? It’s 
certainly going to add some compile time overhead but it can be put behind a 
mode switch in the case it’s worthwhile (the compile time may be negligible in 
many cases). There’s also some optimizations I could think of so I wouldn’t 
give up on implicit specialization  just yet.

I had a look at some old notes I had on the idea of generic helpers since we 
talked about this some years back (for generic arrays) and here's what I found.

2) Right now helpers only support single types but they would need to be 
extended to support “array of T”, “set of T”,which by, why aren’t those 
supported as it is? I can’t seem to think of any reason they should be 
disallowed. The alternative is using an auxiliary generic type which kind of 
confounds things because then you’re extending a new type instead of the 
underlying array of set type.

3) If there was a generic helper for a generic class it may be too verbose to 
use the normal inline specialization syntax ie:

generic THelper = class helper for specialize TMyClass

So I wonder if the shorthand:

generic THelper = class helper for TMyClass

Could be used, providing the type to be extended has a matching generic 
parameter list. At the very least the “specialize” sounds wrong when reading it.

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-25 Thread Hairy Pixels via fpc-pascal



> On Apr 25, 2022, at 7:14 PM, Sven Barth via fpc-pascal 
>  wrote:
> 
> For some reason I don't get all mails by Ryan, so I reply here:
> 
> Helpers currently can't be generic and even if they could be (which I do plan 
> to add) it would require an explicit specialization of the helper to be used 
> because the compiler will not be tasked with searching for potential generic 
> helpers and then implicitly specializing a whole helper type with all its 
> methods to maybe use it for an implicit specialization (and it needs to 
> specialize the helper first to decide whether it even remotely contains 
> suitable methods). 
> 

You could do a search for method names and parameters to see if a generic 
helper was a candidate before specialization. That would reduce the possible 
space for needless specializations right? For non-object types this would be 
even less intrusive since it would only be competing with other helper methods.

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-25 Thread Sven Barth via fpc-pascal
Mattias Gaertner via fpc-pascal  schrieb
am Mo., 25. Apr. 2022, 13:50:

>
> >[...]
> > type
> >   generic TArrayHelper = type helper for array of T
> > procedure Add(value: T);
> >   end;
> >
> > var
> >   a: array of integer;
> > begin
> >   a.Add(1);  // specialize TArrayHelper since the compiler
> > clearly knows the type used is Integer. end.
>

For some reason I don't get all mails by Ryan, so I reply here:

Helpers currently can't be generic and even if they could be (which I do
plan to add) it would require an explicit specialization of the helper to
be used because the compiler will not be tasked with searching for
potential generic helpers and then implicitly specializing a whole helper
type with all its methods to maybe use it for an implicit specialization
(and it needs to specialize the helper first to decide whether it even
remotely contains suitable methods).

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-25 Thread Mattias Gaertner via fpc-pascal
On Mon, 25 Apr 2022 10:15:26 +0700
Hairy Pixels via fpc-pascal  wrote:

>[...]
> For the case of types I understand we must specialize because we’re
> creating a new type each time and there is nothing to infer from the
> context, but for functions it’s backwards, that is we know the types
> being used, we just need to choose the right function based on those
> types.

IMO the important difference is that alias types already safes most
inline specializations.
There is no alias for generic functions, which is why implicit function
specialization is so handy.

 
>[...]
> type
>   generic TArrayHelper = type helper for array of T
> procedure Add(value: T);
>   end;
> 
> var
>   a: array of integer;
> begin
>   a.Add(1);  // specialize TArrayHelper since the compiler
> clearly knows the type used is Integer. end.

IMO that is only useful with modeswitch multihelpers.

All these modeswitches makes it harder to learn Pascal.

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-25 Thread Marco van de Voort via fpc-pascal



On 25-4-2022 11:11, Sven Barth via fpc-pascal wrote:
Then you don't think creative enough. Think about (de)serialization 
code for binary data which needs to use the correct size. If done 
correctly this can very well be handled with a generic.


Actually that's what I immediate thought of too, but nearly all also 
have string as type. Can this be solved by having a specific overloaded 
version for string ?


I'm thinking of things like TStream helpers in streamex.

___
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-25 Thread Hairy Pixels via fpc-pascal


> On Apr 25, 2022, at 4:11 PM, Sven Barth  wrote:
> 
> Then you don't think creative enough. Think about (de)serialization code for 
> binary data which needs to use the correct size. If done correctly this can 
> very well be handled with a generic. 
> 

Oh yes that’s right. I guess I would need some real examples of a function that 
used type information and could suffer a failure by the compiler assuming the 
wrong type from a constant like “1”. If you were deserializing you would 
probably be passing in a very particular type and not some ambiguous thing like 
a number literal.

Having said that there should be type restrictions for Integer, Real, Boolean 
and String (maybe Char) etc… Right now only class, record and interface are 
supported.

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-25 Thread Sven Barth via fpc-pascal
Hairy Pixels via fpc-pascal  schrieb am
Mo., 25. Apr. 2022, 10:58:

>
>
> > On Apr 25, 2022, at 2:39 PM, Martin Frb via fpc-pascal <
> fpc-pascal@lists.freepascal.org> wrote:
> >
> > Actually, it's dealing with SmallInt (or ShortInt). And if the
> programmer does not know that, then it might be an issue...
> >
> > Imagine the generic code (something more complex than "Add") would
> somehow do something that differs for SmallInt and Integer. Like using
> "SizeOf(T)".
>
> This is almost a case that requires better type restrictions. If your
> generic function relies specifically on some particular type information
> this is almost not really even a good candidate to be generic at all.
>

Then you don't think creative enough. Think about (de)serialization code
for binary data which needs to use the correct size. If done correctly this
can very well be handled with a generic.

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-25 Thread Hairy Pixels via fpc-pascal



> On Apr 25, 2022, at 2:39 PM, Martin Frb via fpc-pascal 
>  wrote:
> 
> Actually, it's dealing with SmallInt (or ShortInt). And if the programmer 
> does not know that, then it might be an issue...
> 
> Imagine the generic code (something more complex than "Add") would somehow do 
> something that differs for SmallInt and Integer. Like using "SizeOf(T)".

This is almost a case that requires better type restrictions. If your generic 
function relies specifically on some particular type information this is almost 
not really even a good candidate to be generic at all. 

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-25 Thread Martin Frb via fpc-pascal

On 25/04/22 05:15, Hairy Pixels via fpc-pascal wrote:

generic function Add(left, right: T): T;

And the programmer intends to call it like:

Add(1,1);


Why should the programmer need to tell the compiler it’s dealing with Integer 
when it’s so obvious from the types being used?


Actually, it's dealing with SmallInt (or ShortInt). And if the 
programmer does not know that, then it might be an issue...


Imagine the generic code (something more complex than "Add") would 
somehow do something that differs for SmallInt and Integer. Like using 
"SizeOf(T)".


Sure it can be solved by explicit specialization "Add(1,1)".
But to solve it that way, the programmer needs to know... And he might 
not...


___
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-24 Thread Hairy Pixels via fpc-pascal


> On Apr 23, 2022, at 9:09 PM, Hairy Pixels  wrote:
> 
> The two languages I use commonly these days are Swift and C#, both of which 
> do implicit function specialization by default. After you use a generic 
> function a couple times it becomes apparent the compiler could infer the 
> types and it’s less code to write so it’s natural that any language that has 
> generic functions would support this feature.

I was thinking about this more and I actually feel like we got this backwards 
in Pascal and the default should be implicit specialization with manual 
specialization being a fallback for more challenging cases.

If you have a function:

generic function Add(left, right: T): T;

And the programmer intends to call it like:

Add(1,1);

or

var
  a, b: Integer;
begin
  Add(a, b);


Why should the programmer need to tell the compiler it’s dealing with Integer 
when it’s so obvious from the types being used? All the programmer should know 
is that there is type “T” and any type will work (I know, we don’t have type 
constraints for built-in types and yes, we should implement that).

For the case of types I understand we must specialize because we’re creating a 
new type each time and there is nothing to infer from the context, but for 
functions it’s backwards, that is we know the types being used, we just need to 
choose the right function based on those types.

If it’s ever allowed to do generic type helpers (I would like do this also) I 
think the same idea applies. Manually specializing the type doesn’t provide any 
better control then allowing the compiler to specialize based on the type being 
extended.

type
  generic TArrayHelper = type helper for array of T
procedure Add(value: T);
  end;

var
  a: array of integer;
begin
  a.Add(1);  // specialize TArrayHelper since the compiler clearly 
knows the type used is Integer.
end.

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-24 Thread Marco van de Voort via fpc-pascal



Op 24/04/2022 om 04:37 schreef Hairy Pixels via fpc-pascal:

On Apr 23, 2022, at 10:30 PM, Marco van de Voort via fpc-pascal 
 wrote:

Btw since you are afaik an Apple user, did you actually use conformant arrays, 
or do you base this on UCSD/Borland dialects only?

I started with THINK Pascal on classic Mac OS but I never heard of conformant 
arrays. What are they?


It's a ISO pascal feature that is a kind of open array construct where 
you can pass non zero based arrays too. The limitation that dynamic/open 
arrays are always zero based is a Delphi simplification.


It is more or less meant that if to judge the non zero array bounderies 
features, you need to know the whole story.


___
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-23 Thread Hairy Pixels via fpc-pascal



> On Apr 23, 2022, at 10:30 PM, Marco van de Voort via fpc-pascal 
>  wrote:
> 
> Btw since you are afaik an Apple user, did you actually use conformant 
> arrays, or do you base this on UCSD/Borland dialects only?

I started with THINK Pascal on classic Mac OS but I never heard of conformant 
arrays. What are they?

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-23 Thread Marco van de Voort via fpc-pascal


On 23-4-2022 16:09, Hairy Pixels via fpc-pascal wrote:

For 2) I'm also of the opinion of the others: this is unneeded syntactic sugar. 
There is already a way to declare arrays with a specific size and for a 
language it's in nearly all cases not good to provide multiple ways to achieve 
the same.

Getting off topic but personally I think the idea of a range bound for arrays 
has been proven to be a bad idea from the original Pascal spec. Originally when 
learning pascal I think I did 1 indexed arrays but eventually realized it’s 
non-standard across other languages and doesn’t really provide any use. In 
99.99% of cases I always do 0…n so it’s just wasting time at this point. In 
fact I would be really hard pressed to think of a time I did something besides 
0…n…


0..n-1  I might hope.

Btw since you are afaik an Apple user, did you actually use conformant 
arrays, or do you base this on UCSD/Borland dialects only?



As I've written elsewhere: implicit function specializations as a feature might 
not have happened if Delphi did not support them as well, cause like 2) they 
are essentially syntactic sugar as well.

The two languages I use commonly these days are Swift and C#, both of which do 
implicit function specialization by default. After you use a generic function a 
couple times it becomes apparent the compiler could infer the types and it’s 
less code to write so it’s natural that any language that has generic functions 
would support this feature.


IMHO It is like with all shorthands, if an addition causes pitfalls, 
debugging those is usually worse then they ever save.


I've no idea about how that is with this feature (and then most notably 
the integration in the Pascal language, since pitfalls are often due to 
combinations of features)


___
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-23 Thread Thomas Kurz via fpc-pascal
Thank you for continuously enhancing Free Pascal. Happy to see every new 
feature :)

Is there any work ongoing about overloaded properties? E.g.

property x: integer read GetX;
property x[aindex: integer]: integer write SetX;

I know that declaring the property only once and overloading the getters and 
setters work, but sometimes I wish to have different read/readwrite/write 
access for overloaded properties and this is not possible at the moment. 
Furthermore, code completion in Lazarus doesn't show the different parameters 
of overloaded properties.


- Original Message - 
From: Sven Barth via fpc-pascal 
To: fpc-annou...@lists.freepascal.org 
Sent: Wednesday, April 20, 2022, 19:15:15
Subject: [fpc-pascal] Feature announcement: implicit generic function 
specializations

Dear FPC community,

The FPC developers are pleased to announce the implementation of a new 
feature: implicit generic function specializations. This feature was 
implemented by Ryan Joseph, so thank you very much, Ryan.

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.

Assume you have the following function:

=== code begin ===

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

=== code end ===

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

=== code begin ===

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

=== code end ===

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

=== code begin ===

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

=== code end ===

The compiler will automatically determine the type of the generic 
parameters based on the parameters you pass in (this is always done left 
to right). Depending on the passed in parameters (especially if you're 
using constant values like in the example instead of variables) the 
compiler might however pick a different type than you expected. You can 
enforce a specific type by either explicitely specializing the method as 
before or by inserting a type cast. In the example above the compile 
will specialize the call with the parameters “2, 5” using an 8-bit 
signed type (Pascal prefers signed types) instead of a LongInt as in the 
explicit specialization. If you use “LongInt(2), 5” as parameters then 
the compiler will pick that instead, however with “2, LongInt(5)” it 
will still pick an 8-bit type, because the parameter types are 
determined left to right.

If there exists a non-generic overload for which the parameters types 
match exactly, the compiler will pick that instead of specializing 
something anew. So assume you also have the following function in scope:

=== code begin ===

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

=== code end ===

In the case of “Add(2, 5)” the compiler will *not* pick the non-generic 
function, because it determines that an 8-bit type is enough, however if 
you use “Add(LongInt(2), 5)” the compiler will pick the non-generic 
function.

Aside from simple parameters the compiler also supports arrays and 
function/method variables:

=== code begin ===

generic function ArrayFunc(aArg: specialize TArray): T;
var
   e: T;
begin
   Result := Default(T);
   for e in aArg do
 Result := Result + e;
end;

type
   generic TTest = function(aArg: T): T;

generic function Apply(aFunc: specialize TTest; aArg: T): T;
begin
   Result := aFunc(aArg);
end;

function StrFunc(aArg: String): String;
begin
   Result := UpCase(aArg);
end;

function NegFunc(aArg: LongInt): LongInt;
begin
   Result := - aArg;
end;

begin
   Writeln(ArrayFunc([1, 2, 3])); // will write 6
   Writeln(ArrayFunc(['Hello', 'FPC', 'World'])); // will write 
HelloFPCWorld

   Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
   Writeln(Apply(@NegFunc, 42)); // will write -42
end.

=== code end ===

There are of course a few restrictions for this feature:
- all generic parameters must be used in the declaration of the routine 
(implementation only type parameters are not allowed)
- all parameters that have a generic type must not be default 
parameters, they need to be used in the call or their type must have 
been fixed by a parameter further left (as currently default values for 
parameters of a generic type are not supported this is not much of a 
restriction, but should that change (e.g. Default(T)) then this 
restriction will apply)
- the generic routine must not have constant generic parameters (this 
might be extended in the future with e.g. static arrays or file types, 
but for now this restriction stands)
- the

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

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

> On Apr 23, 2022, at 3:40 PM, Sven Barth via fpc-pascal 
>  wrote:
> 
> For 2) I'm also of the opinion of the others: this is unneeded syntactic 
> sugar. There is already a way to declare arrays with a specific size and for 
> a language it's in nearly all cases not good to provide multiple ways to 
> achieve the same.

Getting off topic but personally I think the idea of a range bound for arrays 
has been proven to be a bad idea from the original Pascal spec. Originally when 
learning pascal I think I did 1 indexed arrays but eventually realized it’s 
non-standard across other languages and doesn’t really provide any use. In 
99.99% of cases I always do 0…n so it’s just wasting time at this point. In 
fact I would be really hard pressed to think of a time I did something besides 
0…n…

> 
> As I've written elsewhere: implicit function specializations as a feature 
> might not have happened if Delphi did not support them as well, cause like 2) 
> they are essentially syntactic sugar as well.

The two languages I use commonly these days are Swift and C#, both of which do 
implicit function specialization by default. After you use a generic function a 
couple times it becomes apparent the compiler could infer the types and it’s 
less code to write so it’s natural that any language that has generic functions 
would support this feature.

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-23 Thread Sven Barth via fpc-pascal

Am 22.04.2022 um 23:08 schrieb 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.


I quickly checked the archives and found two suggestions by you:

1) "Name of a var" from 2011 ( 
https://lists.freepascal.org/pipermail/fpc-pascal/2011-November/031256.html 
)


2) "Declaration of arrays" from 2013 ( 
https://lists.freepascal.org/pipermail/fpc-pascal/2013-June/038496.html )


For 1) I'm still of the opinion that it would be useful especially 
considering that we now have {$I %CURRENTROUTINE%} as well.


For 2) I'm also of the opinion of the others: this is unneeded syntactic 
sugar. There is already a way to declare arrays with a specific size and 
for a language it's in nearly all cases not good to provide multiple 
ways to achieve the same.


As I've written elsewhere: implicit function specializations as a 
feature might not have happened if Delphi did not support them as well, 
cause like 2) they are essentially syntactic sugar as well.
Though contrary to your idea they don't provide an alternative way to 
specialize functions, but really provide a way to explicitely declare 
less. It's a real subtle difference between the two situations, but it's 
there.
The main argument however is Delphi compatibility. The amount of users 
that want features from Delphi is much higher than the amount of users 
that require features from MikroPascal and thus features that are 
syntactic sugar will see the light of day much easier.


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-23 Thread Sven Barth via fpc-pascal

Am 23.04.2022 um 00:42 schrieb 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.


I would need to check why it generates two then. Please report this as well.


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.


I had that issue in a different context already and it's related to the 
assembler writer and when it decides a line should be written again 
(cause at the basic level it would write the line comment for each 
instruction of that line and thus it needs to be reset correctly, but 
across functions that should be reset completely of course). I already 
have a fix for that, but as it's buried in a different branch it will be 
a little while longer. ;)


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 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


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 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 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 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 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 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 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 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 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 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 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 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 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 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 Michael Van Canneyt via fpc-pascal



On Fri, 22 Apr 2022, Hairy Pixels via fpc-pascal wrote:

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?)


Because it is a type definition and you can't put type definition in a
function declaration. e.g. function b (a : record x,y : byte end) : byte;
also does not work.

Michael.___
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-21 Thread Hairy Pixels via fpc-pascal



> On Apr 20, 2022, at 1:15 PM, Sven Barth via fpc-pascal 
>  wrote:
> 
>   Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
>   Writeln(Apply(@NegFunc, 42)); // will write -42

For Sven, this reminds me, since we got this merged in now does that mean 
closures are ready? :D

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-21 Thread Hairy Pixels 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

___
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-21 Thread Mattias Gaertner via fpc-pascal
On Thu, 21 Apr 2022 10:00:46 +0200 (CEST)
Michael Van Canneyt via fpc-pascal 
wrote:

> On Thu, 21 Apr 2022, Hairy Pixels via fpc-pascal wrote:
> 
> >
> >  
> >> On Apr 21, 2022, at 3:48 AM, Mattias Gaertner via fpc-pascal
> >>  wrote: 
> >>> Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
> >>> Writeln(Apply(@NegFunc, 42)); // will write -42
> >>> end.  
> >> 
> >> Mind boggling. :)  
> >
> > This was actually your idea if I remember correctly. :) I think you
> > said even Delphi doesn’t do this so I challenged myself to get it
> > done.  
> 
> Delphi does it, but only for methods of a class.
> 
> AFAIK delphi does not support generic "plain" functions.

Delphi has generic methods and still no generic "plain" functions.

Delphi 11 still does not support *nested* implicit specializations. 
For example the Apply with methods gives in Delphi:

E2010 Incompatible types 'T' and 'String'
F2084 Internal Error: AV10D0B8D2(10CB)-R8-0

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-21 Thread Michael Van Canneyt via fpc-pascal



On Thu, 21 Apr 2022, Hairy Pixels via fpc-pascal wrote:





On Apr 21, 2022, at 3:48 AM, Mattias Gaertner via fpc-pascal 
 wrote:


Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
Writeln(Apply(@NegFunc, 42)); // will write -42
end.


Mind boggling. :)


This was actually your idea if I remember correctly. :) I think you said even 
Delphi doesn’t do this so I challenged myself to get it done.


Delphi does it, but only for methods of a class.

AFAIK delphi does not support generic "plain" functions.

Michael.___
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-21 Thread Hairy Pixels via fpc-pascal


> On Apr 21, 2022, at 3:48 AM, Mattias Gaertner via fpc-pascal 
>  wrote:
> 
>> Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
>> Writeln(Apply(@NegFunc, 42)); // will write -42
>> end.
> 
> Mind boggling. :)

This was actually your idea if I remember correctly. :) I think you said even 
Delphi doesn’t do this so I challenged myself to get it done.

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-20 Thread Mattias Gaertner via fpc-pascal
On Wed, 20 Apr 2022 19:15:15 +0200
Sven Barth via fpc-pascal  wrote:

>[...]
> 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.

Sad. This feature really makes generic functions shine.

 
>[...]
> generic function ArrayFunc(aArg: specialize TArray): T;
>[...]
> type
>    generic TTest = function(aArg: T): T;
> 
> generic function Apply(aFunc: specialize TTest; aArg: T): T;
>[...]
> begin
>    Writeln(ArrayFunc([1, 2, 3])); // will write 6
>    Writeln(ArrayFunc(['Hello', 'FPC', 'World'])); // will write 
> HelloFPCWorld
> 
>    Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
>    Writeln(Apply(@NegFunc, 42)); // will write -42
> end.

Mind boggling. :)

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-20 Thread denisgolovan via fpc-pascal
That seriously improves generic code readability. Definitely worth trying to upgrade. Thanks a lot! 20:15, 20 апреля 2022 г., "Sven Barth via fpc-pascal" :Dear FPC community,The FPC developers are pleased to announce the implementation of a new feature: implicit generic function specializations. This feature was implemented by Ryan Joseph, so thank you very much, Ryan.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.Assume you have the following function:=== code begin ===generic function Add(aArg1, aArg2: T): T;begin   Result := aArg1 + aArg2;end;=== code end ===Up to now you could only use this function as follows:=== code begin ===SomeStr := specialize Add('Hello', 'World');SomeInt := specialize Add(2, 5);=== code end ===However with implicit function specializations enabled you can also use it as follows:=== code begin ===SomeStr := Add('Hello', 'World');SomeInt := Add(2, 5);=== code end ===The compiler will automatically determine the type of the generic parameters based on the parameters you pass in (this is always done left to right). Depending on the passed in parameters (especially if you're using constant values like in the example instead of variables) the compiler might however pick a different type than you expected. You can enforce a specific type by either explicitely specializing the method as before or by inserting a type cast. In the example above the compile will specialize the call with the parameters “2, 5” using an 8-bit signed type (Pascal prefers signed types) instead of a LongInt as in the explicit specialization. If you use “LongInt(2), 5” as parameters then the compiler will pick that instead, however with “2, LongInt(5)” it will still pick an 8-bit type, because the parameter types are determined left to right.If there exists a non-generic overload for which the parameters types match exactly, the compiler will pick that instead of specializing something anew. So assume you also have the following function in scope:=== code begin ===function Add(aArg1, aArg2: LongInt): LongInt;begin   Result := aArg1 + aArg2;end;=== code end ===In the case of “Add(2, 5)” the compiler will *not* pick the non-generic function, because it determines that an 8-bit type is enough, however if you use “Add(LongInt(2), 5)” the compiler will pick the non-generic function.Aside from simple parameters the compiler also supports arrays and function/method variables:=== code begin ===generic function ArrayFunc(aArg: specialize TArray): T;var   e: T;begin   Result := Default(T);   for e in aArg do Result := Result + e;end;type   generic TTest = function(aArg: T): T;generic function Apply(aFunc: specialize TTest; aArg: T): T;begin   Result := aFunc(aArg);end;function StrFunc(aArg: String): String;begin   Result := UpCase(aArg);end;function NegFunc(aArg: LongInt): LongInt;begin   Result := - aArg;end;begin   Writeln(ArrayFunc([1, 2, 3])); // will write 6   Writeln(ArrayFunc(['Hello', 'FPC', 'World'])); // will write HelloFPCWorld   Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR   Writeln(Apply(@NegFunc, 42)); // will write -42end.=== code end ===There are of course a few restrictions for this feature:- all generic parameters must be used in the declaration of the routine (implementation only type parameters are not allowed)- all parameters that have a generic type must not be default parameters, they need to be used in the call or their type must have been fixed by a parameter further left (as currently default values for parameters of a generic type are not supported this is not much of a restriction, but should that change (e.g. Default(T)) then this restriction will apply)- the generic routine must not have constant generic parameters (this might be extended in the future with e.g. static arrays or file types, but for now this restriction stands)- the result type is not taken into account, so if only the result type of a routine is generic then an implicit specialization does not work either- function/method pointers to implicit specializations are not yet supported (pointers to explicit specializations are not yet supported either; once this changes the former will change as well)- the compiler will silently discard generic functions that it can't specialize the *declaration* of; however if the declaration can be specialized correctly, but for whatever reason the *implementation* can not then this will trigger a compilation errorThis feature is by and in itself Delphi compatible however there might be differences in what FPC can implicitely specialize and what Delphi can. Especially if Delphi can specialize something 

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

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

Dear FPC community,

The FPC developers are pleased to announce the implementation of a new 
feature: implicit generic function specializations. This feature was 
implemented by Ryan Joseph, so thank you very much, Ryan.


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.


Assume you have the following function:

=== code begin ===

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

=== code end ===

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

=== code begin ===

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

=== code end ===

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


=== code begin ===

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

=== code end ===

The compiler will automatically determine the type of the generic 
parameters based on the parameters you pass in (this is always done left 
to right). Depending on the passed in parameters (especially if you're 
using constant values like in the example instead of variables) the 
compiler might however pick a different type than you expected. You can 
enforce a specific type by either explicitely specializing the method as 
before or by inserting a type cast. In the example above the compile 
will specialize the call with the parameters “2, 5” using an 8-bit 
signed type (Pascal prefers signed types) instead of a LongInt as in the 
explicit specialization. If you use “LongInt(2), 5” as parameters then 
the compiler will pick that instead, however with “2, LongInt(5)” it 
will still pick an 8-bit type, because the parameter types are 
determined left to right.


If there exists a non-generic overload for which the parameters types 
match exactly, the compiler will pick that instead of specializing 
something anew. So assume you also have the following function in scope:


=== code begin ===

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

=== code end ===

In the case of “Add(2, 5)” the compiler will *not* pick the non-generic 
function, because it determines that an 8-bit type is enough, however if 
you use “Add(LongInt(2), 5)” the compiler will pick the non-generic 
function.


Aside from simple parameters the compiler also supports arrays and 
function/method variables:


=== code begin ===

generic function ArrayFunc(aArg: specialize TArray): T;
var
  e: T;
begin
  Result := Default(T);
  for e in aArg do
    Result := Result + e;
end;

type
  generic TTest = function(aArg: T): T;

generic function Apply(aFunc: specialize TTest; aArg: T): T;
begin
  Result := aFunc(aArg);
end;

function StrFunc(aArg: String): String;
begin
  Result := UpCase(aArg);
end;

function NegFunc(aArg: LongInt): LongInt;
begin
  Result := - aArg;
end;

begin
  Writeln(ArrayFunc([1, 2, 3])); // will write 6
  Writeln(ArrayFunc(['Hello', 'FPC', 'World'])); // will write 
HelloFPCWorld


  Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR
  Writeln(Apply(@NegFunc, 42)); // will write -42
end.

=== code end ===

There are of course a few restrictions for this feature:
- all generic parameters must be used in the declaration of the routine 
(implementation only type parameters are not allowed)
- all parameters that have a generic type must not be default 
parameters, they need to be used in the call or their type must have 
been fixed by a parameter further left (as currently default values for 
parameters of a generic type are not supported this is not much of a 
restriction, but should that change (e.g. Default(T)) then this 
restriction will apply)
- the generic routine must not have constant generic parameters (this 
might be extended in the future with e.g. static arrays or file types, 
but for now this restriction stands)
- the result type is not taken into account, so if only the result type 
of a routine is generic then an implicit specialization does not work either
- function/method pointers to implicit specializations are not yet 
supported (pointers to explicit specializations are not yet supported 
either; once this changes the former will change as well)
- the compiler will silently discard generic functions that it can't 
specialize the *declaration* of; however if the declaration can be 
specialized correctly, but for whatever reason the *implementation* can 
not then this will trigger a compilation error


This feature is by and in itself Delphi compatible however there might 
be differences in what FPC can implicitely specialize and what Delphi 
can. Especially if Delphi can specialize something that FPC can