Lazarus

Programming => General => Topic started by: rnfpc on June 23, 2019, 03:00:27 pm

Title: Creating a generic function
Post by: rnfpc on June 23, 2019, 03:00:27 pm
I have following simple procedure to print out an array of strings:

Code: Pascal  [Select]
  1. type
  2.   TArrStr = array of string;
  3. procedure printStrArr(sarr: TArrStr);
  4.   var item: string;
  5.   begin
  6.     for item in sarr do write(item, ',');
  7.     writeln;
  8.   end;
I also need to have similar functions for integers and real numbers. Is there any way to have generic function here that will print any type of printable item array sent to it? I see that generic classes are possible: https://wiki.freepascal.org/Generics and https://wiki.freepascal.org/Generics_proposals

I tried:
Code: Pascal  [Select]
  1. generic procedure printTArr<T>(sarr: T);
  2.   var item: string; // BUT WHAT TO PUT HERE INSTEAD OF STRING?
  3.   begin
  4.     for item in sarr do write(item, ',');
  5.     writeln;
  6.   end;

Is it possible to have simple generic functions?
Title: Re: Creating a generic function
Post by: Thaddy on June 23, 2019, 04:32:05 pm
T
Title: Re: Creating a generic function
Post by: rnfpc on June 23, 2019, 05:18:33 pm
I tried following:
Code: Pascal  [Select]
  1. program rngenericfn;
  2. {$mode objfpc}
  3. generic procedure printTArr<T>(sarr: T);
  4.   var item: T; // BUT WHAT TO PUT HERE INSTEAD OF STRING?
  5.   begin
  6.     for item in sarr do write(item, ',');
  7.     writeln;
  8.   end;
  9.  
  10. begin
  11.   specialize printTArr<integer>([1,2,3]);
  12. end.
But it gives following error:
Code: Pascal  [Select]
  1. mygenericfn.pas(3,8) Fatal: Syntax error, "BEGIN" expected but "identifier GENERIC" found
Also, T is array of integer/string etc and item should be integer/string and not T (array of integer/string).
Title: Re: Creating a generic function
Post by: totya on June 23, 2019, 07:13:59 pm
As I see on the forum:
Quote
This form of generics is not available in FPC 3.0.4

See: https://forum.lazarus.freepascal.org/index.php/topic,40356.msg278769.html#msg278769 (https://forum.lazarus.freepascal.org/index.php/topic,40356.msg278769.html#msg278769)
Title: Re: Creating a generic function
Post by: PascalDragon on June 24, 2019, 09:19:19 am
I tried:
Code: Pascal  [Select]
  1. generic procedure printTArr<T>(sarr: T);
  2.   var item: string; // BUT WHAT TO PUT HERE INSTEAD OF STRING?
  3.   begin
  4.     for item in sarr do write(item, ',');
  5.     writeln;
  6.   end;
You should declare it like this:
Code: Pascal  [Select]
  1. generic procedure printTArr<T>(sarr: array of T); // << declare the element type, not the whole array
  2.   var item: T;
  3.   begin
  4.     for item in sarr do write(item, ',');
  5.     writeln;
  6.   end;
Title: Re: Creating a generic function
Post by: rnfpc on June 24, 2019, 02:30:07 pm
Does it work on your system? On my system, it gives error on the first line only:
Code: Pascal  [Select]
  1. Fatal: Syntax error, "BEGIN" expected but "identifier GENERIC" found
Why is it objecting to term 'generic'?
Title: Re: Creating a generic function
Post by: Thaddy on June 24, 2019, 02:58:18 pm
Because you did not specify  {$mode objfpc} on top of your unit or program.....
Manuals are brilliant to solve these things..... O:-) (That's a rephrase of RTFM  >:D)
 ;D
Title: Re: Creating a generic function
Post by: rnfpc on June 24, 2019, 03:58:26 pm
I have included {$mode objfpc} at top of file (shown in an earlier post in this thread).
Even {$mode delphi} is giving same error.

I am working on Debian Stable Linux with fpc version 3.0.0.

Does this code works on your system? What is version of your fpc?
Title: Re: Creating a generic function
Post by: ASerge on June 24, 2019, 04:13:28 pm
Is there any way to have generic function here that will print any type of printable item array sent to it?
Is it possible to have simple generic functions?
In FPC 3.0 only via generic types:
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. {$MODE DELPHI}
  3. type
  4.   TPrintArray<T> = class(TObject)
  5.   public
  6.     class procedure DoPrint(const A: array of T); static;
  7.   end;
  8.  
  9. class procedure TPrintArray<T>.DoPrint(const A: array of T);
  10. var
  11.   Item: T;
  12. begin
  13.   for Item in A do
  14.     Write(Item, ',');
  15.   Writeln;
  16. end;
  17.  
  18. begin
  19.   TPrintArray<Integer>.DoPrint([1, 2, 3]);
  20.   TPrintArray<string>.DoPrint(['11', '22', '33']);
  21.   Readln;
  22. end.
Title: Re: Creating a generic function
Post by: rnfpc on June 24, 2019, 05:31:05 pm
Yes, this works. But this means for generics, full class has to be defined and it cannot be done with just a generic function.
Title: Re: Creating a generic function
Post by: ASerge on June 24, 2019, 05:41:45 pm
Yes, this works. But this means for generics, full class has to be defined and it cannot be done with just a generic function.
In the new version of FPC it is possible.
Title: Re: Creating a generic function
Post by: totya on June 24, 2019, 05:44:59 pm
In the new version of FPC it is possible.

...as you said in #3

Many people can't read as I see... :)
Title: Re: Creating a generic function
Post by: Thaddy on June 24, 2019, 05:47:09 pm
3.0.0. is several years old. So no wonder it does not work as expected.
This feature works in 3.0.4 and higher.
Title: Re: Creating a generic function
Post by: totya on June 24, 2019, 05:54:30 pm
3.0.0. is several years old. So no wonder it does not work as expected.
This feature works in 3.0.4 and higher.

I have an fpc 3.0.5 (fixes 3.0 branch), and it doesn't work, error message same as above.

Quote
unit1.pas(23,1) Fatal: Syntax error, "BEGIN" expected but "identifier GENERIC" found
Title: Re: Creating a generic function
Post by: Thaddy on June 24, 2019, 06:09:05 pm
Yes, I was mistaken, but it is in 3.2.0 and trunk.
https://wiki.lazarus.freepascal.org/FPC_New_Features_Trunk#Support_for_generic_routines
Title: Re: Creating a generic function
Post by: PascalDragon on June 25, 2019, 09:48:33 am
Is there any way to have generic function here that will print any type of printable item array sent to it?
Is it possible to have simple generic functions?
In FPC 3.0 only via generic types:
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. {$MODE DELPHI}
  3. type
  4.   TPrintArray<T> = class(TObject)
  5.   public
  6.     class procedure DoPrint(const A: array of T); static;
  7.   end;
  8.  
  9. class procedure TPrintArray<T>.DoPrint(const A: array of T);
  10. var
  11.   Item: T;
  12. begin
  13.   for Item in A do
  14.     Write(Item, ',');
  15.   Writeln;
  16. end;
  17.  
  18. begin
  19.   TPrintArray<Integer>.DoPrint([1, 2, 3]);
  20.   TPrintArray<string>.DoPrint(['11', '22', '33']);
  21.   Readln;
  22. end.
You don't need to declare a class, you can also use a record instead (requires {$modeswitch advancedrecords} in mode ObjFPC).
Title: Re: Creating a generic function
Post by: rnfpc on June 25, 2019, 02:32:10 pm
It will be great if you can post here some code using records in this manner.
Title: Re: Creating a generic function
Post by: PascalDragon on June 26, 2019, 03:22:43 pm
Mode Delphi:
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. {$MODE DELPHI}
  3. type
  4.   TPrintArray<T> = record
  5.   public
  6.     class procedure DoPrint(const A: array of T); static;
  7.   end;
  8.      
  9. class procedure TPrintArray<T>.DoPrint(const A: array of T);
  10. var
  11.   Item: T;
  12. begin
  13.   for Item in A do
  14.     Write(Item, ',');
  15.   Writeln;
  16. end;
  17.      
  18. begin
  19.   TPrintArray<Integer>.DoPrint([1, 2, 3]);
  20.   TPrintArray<string>.DoPrint(['11', '22', '33']);
  21.   Readln;
  22. end.

Mode ObjFPC:
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3. {$MODESWITCH ADVANCEDRECORDS}
  4. type
  5.   generic TPrintArray<T> = record
  6.   public
  7.     class procedure DoPrint(const A: array of T); static;
  8.   end;
  9.  
  10. class procedure TPrintArray.DoPrint(const A: array of T);
  11. var
  12.   Item: T;
  13. begin
  14.   for Item in A do
  15.     Write(Item, ',');
  16.   Writeln;
  17. end;
  18.      
  19. type
  20.   { Note: inline specialization in mode ObjFPC requires FPC 3.2.0 or newer,
  21.      but then you can also use generic functions... }
  22.   TPrintArrayInteger = specialize TPrintArray<Integer>;
  23.   TPrintArrayString = specialize TPrintArray<String>;
  24.  
  25. begin
  26.   TPrintArrayInteger.DoPrint([1, 2, 3]);
  27.   TPrintArrayString.DoPrint(['11', '22', '33']);
  28.   Readln;
  29. end.

Both tested with FPC 3.0.4.