Recent

Author Topic: Generic methods, fpc 3.2.2  (Read 9025 times)

big_M

  • Jr. Member
  • **
  • Posts: 91
Generic methods, fpc 3.2.2
« on: November 24, 2021, 04:23:03 pm »
First time trying generics, but I fail. I try to write a generic method that could process different types of maps (int16, int32, double etc). So I tried something like this:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type  
  4.   TInt16Map = Array of Array of int16;
  5.   TInt32Map = Array of Array of int32;  
  6.  
Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. generic procedure Dummy<T>(x,y:integer; map:T);
  4. begin
  5.   map[x,y]:=1;
  6. end;
  7.  

but the compiler doesn't like map[x,y]. (Illegal qualifier)
So, I guess I would have to restrict the possible types to the actual 2d arrays?

Code: Pascal  [Select][+][-]
  1. generic procedure Dummy<T: TInt16Map, TInt32Map>(x,y:integer; map:T);
  2. begin
  3.   map[x,y]:=1;
  4. end;

But that fails with Error: Class or interface type expected, but got "TInt16Map".

Am I right though in assuming that a global method (not a class method) can be generic? I mostly read of generics in the context of classes


« Last Edit: November 25, 2021, 05:52:31 pm by big_M »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11351
  • FPC developer.
Re: Generic methods, fpc 3.2.2
« Reply #1 on: November 24, 2021, 04:29:15 pm »
(I quickly tested in trunk and with
  • [y], behaviour is the same, please file a bug)

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: Generic methods, fpc 3.2.2
« Reply #2 on: November 24, 2021, 06:16:51 pm »
(I quickly tested in trunk and with
  • [y], behaviour is the same, please file a bug)

Will do. And when trying to restrict the types, should that work like in my second example?

Edit: So, when looking at the following example, only the first method works. So the type really has to be either a class or interface? But in that case, should map[x,y] not be illegal anyways?

Code: Pascal  [Select][+][-]
  1. unit UTest;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. type
  11.   TMyArray = Array of Array of int32;
  12.  
  13.   TMyClass = class(TObject)
  14.     data: Array of Array of int32;
  15.   end;
  16.  
  17.  
  18. implementation
  19.  
  20. generic procedure Dummy<T: TMyClass>(x,y:integer; map:T); {works}
  21. begin
  22.   map.data[x,y]:=1;
  23. end;
  24.  
  25. generic procedure Dummy<T: TMyArray>(x,y:integer; map:T); {doesn't work | Class or interface type expected, but got "TMyArray"}
  26. begin
  27.   map[x,y]:=1;
  28. end;
  29.  
  30. generic procedure Dummy<T: integer>(var value:T); {doesn't work | Class or interface type expected, but got "LongInt"}
  31. begin
  32.   value:=1;
  33. end;
  34.  
  35. end.  
« Last Edit: November 24, 2021, 07:34:21 pm by big_M »

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: Generic methods, fpc 3.2.2
« Reply #3 on: November 25, 2021, 05:47:36 pm »
Okey, so I tried the same in Delphi CE just to see if it works there. From what I understand in Delphi global methods cannot be generic, but in fpc they can. So I tried this using classes this time:

Delphi:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. type
  6.   TDummyClass<T> = class(TObject)
  7.     procedure bla(x,y:integer; map:T);
  8.   end;
  9.  
  10. implementation
  11.  
  12. {$R *.dfm}
  13.  
  14. procedure TDummyClass<T>.bla(x,y:integer; map:T);
  15. begin
  16.   map[x,y]:=1;
  17. end;
  18.  
  19. end.

FPC:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. type
  11.   generic TDummyClass<T> = class(TObject)
  12.     procedure bla(x,y:integer; map:T);
  13.   end;
  14.  
  15. implementation
  16.  
  17. {$R *.lfm}
  18.  
  19. procedure TDummyClass.bla(x,y:integer; map:T);
  20. begin
  21.   map[x,y]:=1;
  22. end;
  23.  
  24. end.

Both don't work. FPC gives me the mentioned error "Illegal qualifier" for map[x,y], and Delphi says for the same line "Array type required". I'm confused now. Is this at all supposed to work or not? Ah, btw, when changing the line to map[y] it compiles with FPC, but not with Delphi.
« Last Edit: November 25, 2021, 06:35:43 pm by big_M »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Generic methods, fpc 3.2.2
« Reply #4 on: November 25, 2021, 11:16:39 pm »
Type constraints only support classes and interfaces as well as the keyword record for primitive types and records.

For what you want to achieve you need to generalize the element type of the array:

Code: Pascal  [Select][+][-]
  1. type
  2.   generic TMap<T> = array of array of T;
  3.  
  4. generic procedure Dummy<T>(x,y:integer; map: specialize TMap<T>);
  5. begin
  6.   map[x,y]:=1;
  7. end;

Otherwise the compiler can't know that map might possibly be an array.

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: Generic methods, fpc 3.2.2
« Reply #5 on: November 26, 2021, 12:12:26 pm »
Type constraints only support classes and interfaces as well as the keyword record for primitive types and records.

For what you want to achieve you need to generalize the element type of the array:

Code: Pascal  [Select][+][-]
  1. type
  2.   generic TMap<T> = array of array of T;
  3.  
  4. generic procedure Dummy<T>(x,y:integer; map: specialize TMap<T>);
  5. begin
  6.   map[x,y]:=1;
  7. end;

Otherwise the compiler can't know that map might possibly be an array.

Ah, okay I see. Yes, that makes sense, although I must admit this concept has to sink in a bit.

Thanks!

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: Generic methods, fpc 3.2.2
« Reply #6 on: November 26, 2021, 04:04:05 pm »
Just another question. Inside a generic class, can I specialize another class only once? The second unit compiles, but the first doesn't with:

utest2.pas(29,31) Error: Duplicate identifier "TMap$1$crc237D1D69"
utest2.pas(29,31) Hint: Identifier already defined in utest2.pas at line 18

Is that normal behavior?


Code: Pascal  [Select][+][-]
  1. unit utest2;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. type
  11.  
  12.   generic TMap<T> = class(TObject) end;
  13.  
  14.   //----------------------------------
  15.  
  16.   generic TAvancedMap<T> = class(TObject)
  17.   private
  18.     FMap: specialize TMap<T>;                  {***}
  19.   public
  20.     constructor Create;
  21.   end;
  22.  
  23.   //----------------------------------
  24.  
  25.  
  26. implementation
  27.  
  28. constructor TAvancedMap.Create;
  29. var
  30.   tmpMap: specialize TMap<T>;              {***}
  31. begin
  32.  //do some stuff
  33. end;
  34.  
  35. end.  


Code: Pascal  [Select][+][-]
  1. unit utest2;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. type
  11.  
  12.   generic TMap<T> = class(TObject) end;
  13.  
  14.   //----------------------------------
  15.  
  16.   generic TAvancedMap<T> = class(TObject)
  17.   type
  18.     STMap = specialize TMap<T>;                      {***}
  19.  
  20.   private
  21.     FMap: STMap;                                  {***}
  22.   public
  23.     constructor Create;
  24.   end;
  25.  
  26.   //----------------------------------
  27.  
  28.  
  29. implementation
  30.  
  31. constructor TAvancedMap.Create;
  32. var
  33.   tmpMap: STMap;                               {***}
  34. begin
  35.  //do some stuff
  36. end;
  37.  
  38. end.
  39.  

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: Generic methods, fpc 3.2.2
« Reply #7 on: November 27, 2021, 12:14:44 am »
Here's my take on it...

As simple as I can make it...

Please read the comments I placed in code here, there is no need to test compile this of course.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.   //Following is a blue print to be used later to create an actual type.
  12.   generic test<T>=Class  //create a base template for the compiler to read when needed.
  13.     aField:T;
  14.   End;
  15. // Following are actual types being created using the Generic Template as the reference.
  16. // Specifying a <TYPE> now makes a complete type define using the BASE to start with;
  17.   TNewTypeInt = specialize Test<Integer>; //Now actually Create the type with Integers;
  18.   TNewTypeFloat = specialize Test<Double>;//Now actually create the type with floats;
  19.   //After this the compiler now has two types as if you were to type them out manually yourself.
  20.   //Note: you can only instruct FPC to Specialze once per type, otherwise it's a dup of course.
  21.   //  you would think only a hint of location where it was specilized aready would be enough?
  22.   { TForm1 }
  23.  
  24.   TForm1 = class(TForm)
  25.     Button1: TButton;
  26.     procedure Button1Click(Sender: TObject);
  27.   private
  28.  
  29.   public
  30.  
  31.   end;
  32.  
  33. var
  34.   Form1: TForm1;
  35.   aNewTypeInt :TNewTypeInt; //declare an instance body pointer;
  36.   aNewTypefloat:TNewTypeFloat;//Declare an instance body pointer;
  37.  
  38. implementation
  39.  
  40. {$R *.lfm}
  41.  
  42. { TForm1 }
  43.  
  44. procedure TForm1.Button1Click(Sender: TObject);
  45. begin
  46.    aNewTypeInt := TNewTypeInt.Create; //Create the instance so the the "aField" member has memory.
  47.    aNewTypeFloat:= TNewTypeFloat.Create;// "" "" ect.
  48.    AnewTypeInt.AField := 1;
  49.    AnewtypeFloat.aField := 1.56;
  50.    aNewTypeInt.Free;
  51.    aNewTypeFloat.free;
  52. end;
  53.  
  54. end.
  55.  
  56.  
The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Generic methods, fpc 3.2.2
« Reply #8 on: November 27, 2021, 12:36:38 pm »
Just another question. Inside a generic class, can I specialize another class only once? The second unit compiles, but the first doesn't with:

utest2.pas(29,31) Error: Duplicate identifier "TMap$1$crc237D1D69"
utest2.pas(29,31) Hint: Identifier already defined in utest2.pas at line 18

Is that normal behavior?

It's an already known bug (though surprisingly annoying to fix...). Your second example is the currently suggested workaround.

big_M

  • Jr. Member
  • **
  • Posts: 91
Re: Generic methods, fpc 3.2.2
« Reply #9 on: November 27, 2021, 01:04:21 pm »
It's an already known bug (though surprisingly annoying to fix...). Your second example is the currently suggested workaround.
Ok, good to know :)

And thanks jamie for your examples!

 

TinyPortal © 2005-2018