Re: [fpc-pascal] Feature announcement: implicit generic function specializations
> 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
> 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
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
> 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
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
> 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
> 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
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
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
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
> 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
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
> 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
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
> 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
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
> 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
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
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
Re: [fpc-pascal] Feature announcement: implicit generic function specializations
> 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
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
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
> 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
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
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
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
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
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
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
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
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
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
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
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
> 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
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
> 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
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
> 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
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
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
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
> 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
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
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 tha
[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 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 not,