Recent

Author Topic: Is Meta programming possible with fpc?  (Read 6640 times)

Warfley

  • Hero Member
  • *****
  • Posts: 1761
Re: Is Meta programming possible with fpc?
« Reply #15 on: May 22, 2023, 06:02:11 pm »
Variants are runtime polymorphism. This has ha few downsides, first it only works with certain types, e.g. no structs and no enums. Also because you don't have compiletime information your compiler can't perform error checking for you. And lastly it requires runtime code, which may entail overhead you otherwise wouldn't have.

The c++ is compiletime polymorphism, which is usually preferable to runtime polymorphism, if possible

mercurhyo

  • Sr. Member
  • ****
  • Posts: 253
Re: Is Meta programming possible with fpc?
« Reply #16 on: May 22, 2023, 07:52:02 pm »
variants??? omg those are not array of variant LOL c'mon @Warfley

1) please debug compiled code with variants and compiled code with array of const

 8-)
« Last Edit: May 22, 2023, 07:59:31 pm by mercurhyo »
DEO MERCHVRIO - Linux, Win10pro - Ryzen9XT 24threads + Geforce Rtx 3080SUPRIM
god of financial gain, commerce, eloquence (and thus poetry), messages, communication (including divination), travelers, boundaries, luck, trickery and thieves; he also serves as the guide of souls to the underworld

Warfley

  • Hero Member
  • *****
  • Posts: 1761
Re: Is Meta programming possible with fpc?
« Reply #17 on: May 22, 2023, 08:28:54 pm »
The name is TVarRec which stands for "variant record". It is a variant implementation (one out of two variant implementations pascal has): https://wiki.lazarus.freepascal.org/TVarRec
Quote
A TVarRec is a variant record used with the array of const parameter declaration

mercurhyo

  • Sr. Member
  • ****
  • Posts: 253
Re: Is Meta programming possible with fpc?
« Reply #18 on: May 23, 2023, 12:22:18 am »
The name is TVarRec which stands for "variant record". It is a variant implementation (one out of two variant implementations pascal has): https://wiki.lazarus.freepascal.org/TVarRec
Quote
A TVarRec is a variant record used with the array of const parameter declaration

there is two variants implementation now hahaha whatelse? a variant encapsulating a variant? wowow keep your brain safe  :P :D :D :D
DEO MERCHVRIO - Linux, Win10pro - Ryzen9XT 24threads + Geforce Rtx 3080SUPRIM
god of financial gain, commerce, eloquence (and thus poetry), messages, communication (including divination), travelers, boundaries, luck, trickery and thieves; he also serves as the guide of souls to the underworld

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1216
Re: Is Meta programming possible with fpc?
« Reply #19 on: May 23, 2023, 01:27:38 am »
hmhm I wonder who told you about "diamond of death"  :D

about "writeln" accepting many parameters you can do it yourself with any procedure/function you wrrite

 :P

https://www.freepascal.org/docs-html/ref/refsu69.html


I remember the term variant record from a beginning programming book as being a record with a tag field, the value of which would control if there were extra fields. It seems like the things discussed here are much more complicated than that. Thanks for all the interesting information everyone.
« Last Edit: May 23, 2023, 11:13:49 am by Martin_fr »
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Warfley

  • Hero Member
  • *****
  • Posts: 1761
Re: Is Meta programming possible with fpc?
« Reply #20 on: May 23, 2023, 12:18:28 pm »

there is two variants implementation now hahaha whatelse? a variant encapsulating a variant? wowow keep your brain safe  :P :D :D :D

There are two types of variants, first there is the type variant, which is managed by a lot of compiler magic. The second type are so called variant records, which are records where memory is shared between fields.

The type variant is a lot more complex but more powerful (e.g. it can hold managed types, which variant records can't), while variant records are rather low level and requires some more manual work.

But in essence, both of them are runtime polymorphism, which means all of the problems I outlined above, and whenever you can replace them with compile time polymorphism you should do it.

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1216
Re: Is Meta programming possible with fpc?
« Reply #21 on: May 23, 2023, 06:20:48 pm »
I’ve never used variant type. I’m curious why it’s necessary? Doesn’t it go contrary to the strong typing that pascal is famous for?
Also if a variant type variable can hold different types how do you know what type it contains at any given moment before trying to use it?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

PascalDragon

  • Hero Member
  • *****
  • Posts: 5755
  • Compiler Developer
Re: Is Meta programming possible with fpc?
« Reply #22 on: May 23, 2023, 09:58:30 pm »
The name is TVarRec which stands for "variant record". It is a variant implementation (one out of two variant implementations pascal has): https://wiki.lazarus.freepascal.org/TVarRec
Quote
A TVarRec is a variant record used with the array of const parameter declaration

there is two variants implementation now hahaha whatelse? a variant encapsulating a variant? wowow keep your brain safe  :P :D :D :D

In fact any record type with a case-part is a variant record. Variant and TVarRec are simply two that are more intertwined with the compiler. Another important one is Rtti.TValue.

I’ve never used variant type. I’m curious why it’s necessary? Doesn’t it go contrary to the strong typing that pascal is famous for?
Also if a variant type variable can hold different types how do you know what type it contains at any given moment before trying to use it?

The Variant type was originally introduced for late binding COM support on Windows as it allows you to call functions that don't exist as such, but are instead available through some serialization mechanism. This isn't restricted to COM however as for example the Python4Delphi library makes use of that to wrap Python objects.

Akira1364

  • Hero Member
  • *****
  • Posts: 561
Re: Is Meta programming possible with fpc?
« Reply #23 on: May 23, 2023, 10:42:37 pm »
Variants are runtime polymorphism. This has ha few downsides, first it only works with certain types, e.g. no structs and no enums. Also because you don't have compiletime information your compiler can't perform error checking for you. And lastly it requires runtime code, which may entail overhead you otherwise wouldn't have.

The c++ is compiletime polymorphism, which is usually preferable to runtime polymorphism, if possible

Even without getting into generics-based stuff with FPC, you can do interesting things with the "implicit" operator overload and arrays if you need to support multiple types, in a way that's a bit more performant than normal variants generally will be:

Code: Pascal  [Select][+][-]
  1. program Test;
  2.  
  3. {$Mode ObjFPC}
  4. {$ModeSwitch AdvancedRecords}
  5. {$ModeSwitch TypeHelpers}
  6. {$ImplicitExceptions Off}
  7.  
  8. uses SysUtils;
  9.  
  10. type
  11.   TPrimRec = record
  12.     class operator := (const LHS: SizeInt): TPrimRec; inline;
  13.     class operator := (const LHS: SizeUInt): TPrimRec; inline;
  14.     class operator := (const LHS: Double): TPrimRec; inline;
  15.     class operator := (const LHS: Boolean): TPrimRec; inline;
  16.     class operator := (const LHS: Char): TPrimRec; inline;
  17.     class operator := (const LHS: WideChar): TPrimRec; inline;
  18.     class operator := (const LHS: ShortString): TPrimRec; inline;
  19.     class operator := (const LHS: PChar): TPrimRec; inline;
  20.     class operator := (const LHS: PWideChar): TPrimRec; inline;
  21.     procedure Print(const TextPtr: PText);
  22.     case VType : Byte of
  23.       0 : (VSignedInt: SizeInt);
  24.       1 : (VUnsignedInt: SizeUInt);
  25.       2 : (VFloat: Double);
  26.       3 : (VBoolean: Boolean);
  27.       4 : (VChar: Char);
  28.       5 : (VWideChar: WideChar);
  29.       6 : (VShortString: ShortString);
  30.       7 : (VString: PChar);
  31.       8 : (VUString: PWideChar);
  32.     end;
  33.  
  34.     PPrimRec = ^TPrimRec;
  35.  
  36.     TPrimRecArray = array of TPrimRec;
  37.  
  38. class operator TPrimRec.:= (const LHS: SizeInt): TPrimRec;
  39. begin
  40.   Result.VType := 0;
  41.   Result.VSignedInt := LHS;
  42. end;
  43.  
  44. class operator TPrimRec.:= (const LHS: SizeUInt): TPrimRec;
  45. begin
  46.   Result.VType := 1;
  47.   Result.VUnsignedInt := LHS;
  48. end;
  49.  
  50. class operator TPrimRec.:= (const LHS: Double): TPrimRec;
  51. begin
  52.   Result.VType := 2;
  53.   Result.VFloat := LHS;
  54. end;
  55.  
  56. class operator TPrimRec.:= (const LHS: Boolean): TPrimRec;
  57. begin
  58.   Result.VType := 3;
  59.   Result.VBoolean := LHS;
  60. end;
  61.  
  62. class operator TPrimRec.:= (const LHS: Char): TPrimRec;
  63. begin
  64.   Result.VType := 4;
  65.   Result.VChar := LHS;
  66. end;
  67.  
  68. class operator TPrimRec.:= (const LHS: WideChar): TPrimRec;
  69. begin
  70.   Result.VType := 5;
  71.   Result.VWideChar := LHS;
  72. end;
  73.  
  74. class operator TPrimRec.:= (const LHS: ShortString): TPrimRec;
  75. begin
  76.   Result.VType := 6;
  77.   Result.VShortString := LHS;
  78. end;
  79.  
  80. class operator TPrimRec.:= (const LHS: PChar): TPrimRec;
  81. begin
  82.   Result.VType := 6;
  83.   Result.VString := LHS;
  84. end;
  85.  
  86. class operator TPrimRec.:= (const LHS: PWideChar): TPrimRec;
  87. begin
  88.   Result.VType := 7;
  89.   Result.VUString := LHS;
  90. end;
  91.  
  92. procedure TPrimRec.Print(const TextPtr: PText);
  93. begin
  94.   case VType of
  95.     0 : Write(TextPtr^, VSignedInt, ' ');
  96.     1 : Write(TextPtr^, VUnsignedInt, ' ');
  97.     2 : Write(TextPtr^, VFloat.ToString, ' ');
  98.     3 : Write(TextPtr^, VBoolean, ' ');
  99.     4 : Write(TextPtr^, VChar, ' ');
  100.     5 : Write(TextPtr^, VWideChar, ' ');
  101.     6 : Write(TextPtr^, VShortString, ' ');
  102.     7 : Write(TextPtr^, VString, ' ');
  103.     8 : Write(TextPtr^, WideString(VUString), ' ');
  104.   end;
  105. end;
  106.  
  107. procedure PrintLn(constref A: array of TPrimRec);
  108. var
  109.   PR: PPrimRec;
  110.   IO: PText;
  111. begin
  112.   IO := @System.Output;
  113.   PR := @A[0];
  114.   repeat
  115.     PR^.Print(IO);
  116.     Inc(PR);
  117.   until (PR > @A[High(A)]);
  118. end;
  119.  
  120. begin
  121.   PrintLn(['blahblah', 1, 19.433, false, 'アイウエオ', -100, #36]);
  122. end.
  123.  

Recreating WriteLn like that isn't super useful in real life obviously, it was just to serve as an example basically.

Warfley

  • Hero Member
  • *****
  • Posts: 1761
Re: Is Meta programming possible with fpc?
« Reply #24 on: May 23, 2023, 11:27:42 pm »
I’ve never used variant type. I’m curious why it’s necessary? Doesn’t it go contrary to the strong typing that pascal is famous for?
Also if a variant type variable can hold different types how do you know what type it contains at any given moment before trying to use it?

Variant is a form of runtime polymorphism. Polymorphism is when you have the same code (from a callers perspective) handling different data types transparently. Generally you can distinguish between runtime polymorphism, where the type of data is only known at runtime, and compiletime polymorphism, where the compiler already knows the type.
First as an example of the latter, the most simple form is function overloading
Code: Pascal  [Select][+][-]
  1. procedure Foo(x: integer);
  2. begin
  3.   WriteLn('Integer: ', x);
  4. end;
  5.  
  6. procedure Foo(x: String);
  7. begin
  8.   WriteLn('String: ', x);
  9. end;

You can now use the function Foo on an integer or string parameter, and the compiler will figure out which of those implementations to call. So you have the same function for multiple data types that is decided on compiletime, i.e. compiletime polymorphism. Also the compiler does not create any runtime code for checking if x is really an integer during runtime, because the full disambiguation happens at compiletime. Besides this, when you write Foo(3.14) the compiler can see that there is no definition for floats, and throws an error.

So compiletime polymorphism is usually very efficient and allows the compiler to perform full typechecks.

Runtime polymorphism on the other hand is when the type is only known at runtime, e.g. with variant:
Code: Pascal  [Select][+][-]
  1. procedure Foo(v : Variant);
  2. begin
  3.  Case varType(v) of
  4.     varString:
  5.         Writeln('String: ', String(v));
  6.     varInteger:
  7.         Writeln('Integer: ', Integer(v));
  8.  else
  9.    Writeln('Unable to determine variant type');
  10.  end;
  11. end;
Like before this function accepts strings and integers, but it uses the case statement to check which code to execute. This has two side effects. First the case statement is runtime code, so it will be compiled in and require extra execution time, so this code is less efficient as the compiletime example above. Second because variant can be a lot of different types (anything except records, objects and enums), even contain no data at all, you can also call Foo(3.14) and your code compiles fine. It will just during execution print a runtime error that this type is not supported.

So compared to compiletime polymorphism, runtime polymorphism is less efficient and has no compiler error checking. Also usually requires much more and less readable code. Therefore whenever you need polymorphism, but compiletime polymorphism is fully sufficient, you should use it.

Variant and array of const are especially bad, because they allow for all kinds of data. With your own variant records or even non variant records with just two fields (for managed types useful).
For exa.ple I have created a union type, which can hold one of two types: https://github.com/Warfley/ObjPasUtils/tree/master/src/dynamictypes#tuniont-u
Using this the function would look like this:
Code: Pascal  [Select][+][-]
  1. procedure Foo(u : TUnion<String, Integer>);
  2. begin
  3.   If u.IsFirst then // first type is String
  4.     WriteLn('String :', u.First)
  5.   else if u.IsSecond then // second is Integer
  6.     WriteLn('Integer: ', u.Second)
  7.   else
  8.     WriteLn('Error u is empty);
  9. end;

This now only allows for strings and integers, meaning Foo(3.14) will throw a compiler error. But still allows for empty values (Foo(None)) and also still adds runtime overhead. So still worse than the compiletime polymorphism alternative

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1216
Re: Is Meta programming possible with fpc?
« Reply #25 on: May 24, 2023, 12:15:36 am »
i tried this
Code: Pascal  [Select][+][-]
  1. var v:variant;
  2.  BEGIN
  3.  v:= 'str';
  4. case vartype(v) of
  5.     varinteger:ShowMessage(v.ToString);
  6.     varstring:ShowMessage(v);
  7.     end;  
  8.  
and it gives these warnings
Quote
tester_2023.pas(74,6) Note: Call to subroutine "operator :=(const source:ShortString):Variant;" marked as inline is not inlined
tester_2023.pas(76,38) Note: Call to subroutine "operator :=(const source:OleVariant):AnsiString;" marked as inline is not inlined
tester_2023.pas(77,28) Note: Call to subroutine "operator :=(const source:Variant):AnsiString;" marked as inline is not inlined
what do these warnings about inline mean?
also does anyone know how to select multiple messages before copying them?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Is Meta programming possible with fpc?
« Reply #26 on: May 24, 2023, 02:11:54 am »
I don't know why operators are not inlined.

You can select multiple messages by left mouse click + Ctrl or Shift. Then right click -> Copy -> Copy selected messages to clipboard.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Warfley

  • Hero Member
  • *****
  • Posts: 1761
Re: Is Meta programming possible with fpc?
« Reply #27 on: May 24, 2023, 10:11:05 am »
and it gives these warnings
Quote
tester_2023.pas(74,6) Note: Call to subroutine "operator :=(const source:ShortString):Variant;" marked as inline is not inlined
tester_2023.pas(76,38) Note: Call to subroutine "operator :=(const source:OleVariant):AnsiString;" marked as inline is not inlined
tester_2023.pas(77,28) Note: Call to subroutine "operator :=(const source:Variant):AnsiString;" marked as inline is not inlined
what do these warnings about inline mean?
also does anyone know how to select multiple messages before copying them?

Those aren't warnings, those are notes, and can be safely ignored. It just means that these operators where marked as inline but the compiler decided not to inline them. Inking is to rather than creating a function call, to just put the contents of the function in the place of the call directly. This makes the code usually more speed efficient at the cost of a few bytes of memory

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1216
Re: Is Meta programming possible with fpc?
« Reply #28 on: May 24, 2023, 03:15:44 pm »
You can select multiple messages by left mouse click + Ctrl or Shift. Then right click -> Copy -> Copy selected messages to clipboard.
Thanks for the info, unfortunately I’m using a laptop with trackpad. I’m not sure how to make that wo even trying what would usually be considered a right clicks while holding control and/or shift key

I was chatting with someone recently who told me that pascal has variants so that it can utilize code from c libraries. Suffice it to say that I was not thrilled to find out about dependencies on c  :o
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Is Meta programming possible with fpc?
« Reply #29 on: May 24, 2023, 03:42:13 pm »
The context-menu key does not work for me too. It's Lazarus+Qt5. (It's that key by the right Ctrl).
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

 

TinyPortal © 2005-2018