Lazarus

Programming => General => Topic started by: trn76 on November 04, 2019, 09:48:41 am

Title: Generics and type <T> determination?
Post by: trn76 on November 04, 2019, 09:48:41 am
In a generic class, how can I determine if the type T is a ordinal/integer or float? Just like SizeOf() that determines the size when compiling, and not runtime.
This is just an example, as you see in the function divXY - if <T> is ordinal use "div", if <T> is a float then use "/".... and so on.


Code: Pascal  [Select]
  1. unit ugenerictest;
  2.  
  3. {$MODE objfpc}{$H+}
  4. {$MODESWITCH AdvancedRecords}
  5. {$IFDEF FPC}
  6.   {$PACKRECORDS C}
  7. {$ENDIF}
  8. {$INLINE ON}
  9.  
  10. interface
  11.  
  12. type
  13.  
  14.   generic TGGenericPoint<T> = packed record
  15.     public
  16.       x, y        : T;
  17.       procedure   flip; inline;
  18.       procedure   invert; inline;
  19.       function    longest: T;
  20.       function    shortest: T;
  21.       function    divXY: T;
  22.   end;
  23.  
  24. implementation
  25.  
  26. procedure TGGenericPoint.flip;
  27. var a: T;
  28. begin
  29.   a := x;
  30.   x := y;
  31.   y := a;
  32. end;
  33.  
  34. procedure TGGenericPoint.invert;
  35. begin
  36.   x := -x;
  37.   y := -y;
  38. end;
  39.  
  40. function TGGenericPoint.longest: T;
  41. begin
  42.   if x >= y
  43.     then Result := x
  44.     else Result := y;
  45. end;
  46.  
  47. function TGGenericPoint.shortest: T;
  48. begin
  49.   if x <= y
  50.     then Result := x
  51.     else Result := y;
  52. end;
  53.  
  54. function TGGenericPoint.divXY: T;
  55. begin
  56.   Result := x / y;  // <--- how can the compiler determine if we are dealing with integer or float?
  57. end;
  58.  
  59.  
  60.  
Title: Re: Generics and type <T> determination?
Post by: Mr.Madguy on November 04, 2019, 10:22:27 am
If you have to determine <T> type at runtime, than generics isn't right way to do your job, cuz they're intended to be universal. Use standard OOP features instead.

Not sure, if Lazarus supports this operation. Latest Lazarus versions should allow it. But you can just specialize your generic for certain type.

For example (Delphi syntax, as I'm not familiar to Lazarus one):
Code: Pascal  [Select]
  1. type
  2.   TBaseClass<T> = class
  3.     function DoSomething(const A, B:T):T;virtual;abstract;
  4.   end;
  5.  
  6.   TIntegerClass = class(TBaseClass<Integer>)
  7.     function DoSomething(const A, B:Integer):Integer;override;  
  8.   end;
  9.  
Title: Re: Generics and type <T> determination?
Post by: Thaddy on November 04, 2019, 11:46:06 am
Simply check the type kind by using GetTypeKind.
Small example:
Code: Pascal  [Select]
  1. {$mode delphi}{$H+}
  2. function WhatAmI<T>(const value:T):string;
  3. begin
  4.   writestr(Result,gettypekind(Value));
  5. end;
  6.  
  7. var
  8.  i:integer = 0;
  9.  d:double = 0.0;
  10. begin
  11.   writeln(WhatAmI<Integer>(i));
  12.   writeln(WhatAmI<Double>(d));
  13. end.

Since typekind itself is an ordinal, you can make a set of types that behave a certain way, like ordinals and floats.
so:
Code: Pascal  [Select]
  1. uses typinfo;// for ttypekinds set
  2. type
  3.   TBaseClass<T> = class
  4.     function DoSomething(const A, B:T):T;virtual;abstract;
  5.     function WhatAmI:TTypeKind;
  6.   end;
  7.  
  8.     function TBaseClass.WhatAmI:TTypeKind;
  9.     begin
  10.       Result := GetTypeKind(T);
  11.    end;
Title: Re: Generics and type <T> determination?
Post by: trn76 on November 08, 2019, 02:11:21 pm
Ok, thanks people.. Would be nice if there was a compile-time way, generics are really useful and powerful.
Title: Re: Generics and type <T> determination?
Post by: Thaddy on November 08, 2019, 03:29:03 pm
Ok, thanks people.. Would be nice if there was a compile-time way, generics are really useful and powerful.
The compile time way is the programmer.... I know that is not always a very satisfactory solution...
Title: Re: Generics and type <T> determination?
Post by: PascalDragon on November 09, 2019, 10:52:18 am
Ok, thanks people.. Would be nice if there was a compile-time way, generics are really useful and powerful.
You can take a look at this (https://lists.freepascal.org/pipermail/fpc-pascal/2019-November/057113.html) solution I posted on the mailing list last night that deals with a similar problem. Maybe you can make use of that. Please note however that GetTypeKind requires FPC 3.2 or newer.