Recent

Author Topic: Explaining Generics and Specialization (as understood by me -a hobbyist)  (Read 824 times)

Ten_Mile_Hike

  • Full Member
  • ***
  • Posts: 101
My post had way too many errors. Removed as a courtesy to those with functioning brains
« Last Edit: March 23, 2025, 03:55:49 am by Ten_Mile_Hike »
When any government, or any church for that matter, undertakes to say to its subjects, This you may not read, this you
must not see, this you are forbidden to know, the end result is tyranny and oppression no matter how holy the motives.

Robert A. Heinlein

Boleeman

  • Hero Member
  • *****
  • Posts: 897
I have a mixed understanding of Generics. Always had to experiment and fiddle around a bit a bit to get it working (and sometimes avoided it altogether).

What I had problems with was:
specialize to a type instead of a var and code verbosity between Delphi mode and ObjFPC mode.
Tried to learn it from different sample codes but later realized there were differences in syntax for Delphi and FreePascal.

Syntax like TSpeaker.specialize Say<Integer>(42);  and  FooTest = specialize Test<integer>;   
like in this post at https://forum.lazarus.freepascal.org/index.php/topic,70597.msg550457.html#msg550457 :

Code: Pascal  [Select][+][-]
  1. program TestGeneric;
  2.  
  3. {$mode objfpc}
  4.  
  5. type
  6.   TSpeaker = class
  7.     generic class procedure Say<T>(AMessage: T);
  8.   end;
  9.  
  10. generic class procedure TSpeaker.Say<T>(AMessage: T);
  11. begin
  12.   Writeln('Says: ', AMessage);
  13. end;
  14.  
  15. begin
  16.   TSpeaker.specialize Say<Integer>(42);
  17. end.

and here:

Code: Pascal  [Select][+][-]
  1.     program project1;
  2.     {$mode objfpc}
  3.       generic function Test<T>(var V: T): boolean;
  4.       begin
  5.         result := true;
  6.       end;
  7.      
  8.     type
  9.         FooTest = specialize Test<integer>;// after this all code is the same in both modes
  10.         Foo = integer;
  11.     var
  12.       V1: Integer;
  13.     begin
  14.       if fooTest(V1) then
  15.         write(1);
  16.     end.

whereas in this post you specialize the variable like:

var
  IntBox: specialize TBox<Integer>;




Thanks Ten_Mile_Hike for nice post on Generics.
(username sort of implies that you walk "Ten Miles to get back home")
« Last Edit: March 22, 2025, 10:43:17 pm by Boleeman »

jamie

  • Hero Member
  • *****
  • Posts: 6880
You got long winded so I'll shoot from the hip.

You commented about inherited classes being duplicated if the descendant class is different, which I believe is what you said?

 But that isn't true, if the inherited class is not effected by the TYPE in a generic declaration then it remains the same code fragment for lets say 1000 different classes you make using that inherited class. The inheritance body codes gets call at a single point for all classes same or different. The difference is the data segment allocated for any of the variables, tables etc.


I hope I said that correctly.


The only true wisdom is knowing you know nothing

Ten_Mile_Hike

  • Full Member
  • ***
  • Posts: 101
@jamie   I certainly trust your take on it. I am still a novice just trying to figure this stuff out.
              Yes; I made it a long post on purpose in the hope that it would help myself and other
              beginners to get a firmer grasp on the concepts via the "Explain it like I'm five"
              method.

              Thanks for the input.
When any government, or any church for that matter, undertakes to say to its subjects, This you may not read, this you
must not see, this you are forbidden to know, the end result is tyranny and oppression no matter how holy the motives.

Robert A. Heinlein

cdbc

  • Hero Member
  • *****
  • Posts: 2108
    • http://www.cdbc.dk
Hi
I don't know why, but standalone generic functions like this:
Code: Pascal  [Select][+][-]
  1. generic function Test<T>(var V: T): boolean;
  2.       begin
  3.         result := true;
  4.       end;
Codetools don't like so much (not at all)...
All the other generic ways, codetools don't mind. Mysterious.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Thaddy

  • Hero Member
  • *****
  • Posts: 16820
  • Ceterum censeo Trump esse delendam
What I had problems with was:
specialize to a type instead of a var and code verbosity between Delphi mode and ObjFPC mode.
What is not clear about that?
There are two distinct advantages for specializing to a type:
- After the specialization the code looks the same independent of mode Delphi or ObjFpc
- You get rid of the shoutiness and duplication of code that you have when specializing to a var.
Code: Pascal  [Select][+][-]
  1. program testspec1;
  2. {$mode objfpc}
  3. uses fgl;
  4.  
  5. type
  6.   TMyIntegerList = specialize TFPGlist<integer>;
  7.  
  8. var
  9.   L1:TMyIntegerList;
  10.   L2:specialize TFPGList<integer>;
  11. begin
  12.   { simple and clean syntax }
  13.   L1 := TMyIntegerList.Create;
  14.   { dirty and verbose syntax because of duplication of specialize}
  15.   L2 := specialize TFPGList<integer>.Create;
  16.   L2.Free;
  17.   L1.Free;  
  18. end.

Now the same in Delphi mode, which is less verbose, but here a specialization to a type also has advantages:
Code: Pascal  [Select][+][-]
  1. program testspec2;
  2. {$mode delphi}
  3. uses fgl;
  4.  
  5. type
  6.   TMyIntegerList = TFPGlist<integer>;
  7.  
  8. var
  9.   L1:TMyIntegerList;
  10.   L2:TFPGList<integer>;
  11. begin
  12.   { simple and clean syntax }
  13.   L1 := TMyIntegerList.Create;
  14.   { dirty and verbose syntax because of duplication of specialize}
  15.   L2 := TFPGList<integer>.Create;
  16.   L2.Free;
  17.   L1.Free;  
  18. end.

Now when you mix modes a lot, like I do, specialization to a type can save you a lot of work:
Code: Pascal  [Select][+][-]
  1. { either mode delphi or objfpc here }
  2. uses fgl;
  3.  
  4. type
  5.   { if you switch modes the only thing in your code that
  6.     needs to change is this bit, nothing more
  7.     This for $mode delphi }
  8.   TMyIntegerList = TFPGlist<integer>;
  9.   { into this for $mode objfpc }
  10.   TMyIntegerList = specialize TFPGList<integer>;
  11. var
  12.   L1:TMyIntegerList;
  13. begin
  14.   { simple and clean syntax, all code is unaffected by the mode }
  15.   L1 := TMyIntegerList.Create;
  16.   L1.Free;  
  17. end.

I hope you now understand the adagium to specialize to a type and not a var.

I must note there are slight exceptions to this rule in very, very, very, very rare cases that you probably do not come across ever.

Specialization to a var is allowed but in 99% of all cases simply demonstrably bad programming.

The verbosity of the syntax is just historical: Freepascal had generics way before Delphi had.


« Last Edit: March 23, 2025, 12:00:10 pm by Thaddy »
Changing servers. thaddy.com may be temporary unreachable but restored when the domain name transfer is done.

 

TinyPortal © 2005-2018