Recent

Author Topic: converting C++ over laz, issues with template operators conversion  (Read 13277 times)

jamie

  • Hero Member
  • *****
  • Posts: 6077
Does any one have a suggestion as to how to get this working In laz/fpc?
I know we can't use << or >> as operator overloads so I was going to use something different..

even a simple := will do but I can't seem to come up with an operator overload that works with a  <T> define.
Code: Pascal  [Select][+][-]
  1.         ////////////////////////////////////////////////////
  2.         // The default operators
  3.         //
  4.         template<class T> CStream &operator<<(const T& a)
  5.         {
  6.                 Write(&a, sizeof(T));
  7.                 return *this;
  8.         }
  9.  
  10.         template<class T> CStream &operator>>(T& a)
  11.         {
  12.                 Read(&a, sizeof(T));
  13.                 return *this;
  14.         }
  15.  

Cstream is the class, I need to have a operator defined that accepts a generic for type etc..
how would I go about this ? It has to remain as a class not a record.

The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: converting C++ over laz, issues with template operators conversion
« Reply #1 on: February 21, 2021, 05:13:20 pm »
It might be better to use a fluent interfaces approach instead as FPC neither supports generic operator overloads nor implicit conversions that would be required nor operators inside classes. Instead you might want to do a "fluent interface" approach:

Code: Pascal  [Select][+][-]
  1. program topovld;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeswitch advancedrecords}
  5.  
  6. type
  7.   TMyTest = class
  8.     generic function Add<T>(aArg: T): TMyTest;
  9.   end;
  10.  
  11. { TMyTest }
  12.  
  13. generic function TMyTest<T>.Add(aArg: T): TMyTest;
  14. begin
  15.   { whatever }
  16.   Result := Self;
  17. end;
  18.  
  19. var
  20.   t: TMyTest;
  21. begin
  22.   t.specialize Add<LongInt>(42).specialize Add<String>('Hello');
  23. end.

Ryan Joseph is currently working on a feature (called implicit function specializations) that would shorten the calls to this:

Code: Pascal  [Select][+][-]
  1. t.Add(42).Add('Hello');

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: converting C++ over laz, issues with template operators conversion
« Reply #2 on: February 22, 2021, 09:26:12 am »
What would really be nice is a way for the compiler to do this


MyFunction(obj; SizeOfOjb:Integer = Sizeof(Obj):someOptionalReturnType;

Since the compiler knows at compile time the size of each type coming in the pipe it should be able to insert the size of the object on the fly

For example

 MyFunction(AnIntegerOfSomeSort);

The compiler would then generate code like this

 MyFunction(AnIntegerOfSomeSort, SizeOf(Obj)=4);

 basically a way to know how large of an object the first parameter is looking at..

I don't understand what you're trying to achieve here.

However what stops you from doing something like this:

Code: Pascal  [Select][+][-]
  1. procedure FoobarInternal(const aArg; aSize: SizeInt);
  2. begin
  3.   // whatever
  4. end;
  5.  
  6. generic procedure Foobar<T>(const aArg: T);
  7. begin
  8.   FoobarInternal(aArg, SizeOf(aArg));
  9. end;

Also it would be nice if some how the compiler could build an "array of reference" instead of CONST so one could write back to the source elements or make faster code for the compiler to simply supply refence instead of copying over all the elements thus forming an array of pointers..

 Procedure MyElements(Array of Refence);

 MyElements([SomeInteger, SomeWord, SomeVariant, SomeString]);

 basically the array would be the TYPE and only the Pointer to the item.. so the TYPE would be the source of the element not a pointer but the element of the Variant record would define the pointer to the source element..

  Or did I miss something ?

Best use an array of pointers and an additional parameter that describes what these pointers point to (similar to what SScanf does).

They almost do work actually but there appears to be a bug in the compiler///

No, there is not. Classes are implicit pointers types. Thus you're essentially operating either on garbage or on a Nil value (likely the former if it doesn't crash right away). You need to explicitly instantiate the result:

Code: Pascal  [Select][+][-]
  1. operator := (R: String): TForm1;
  2. begin
  3.   Result := TForm1.Create(Nil);
  4.   Result.Caption := R;
  5. end;

Operators can not modify the left side. It might feel like this for records and objects due to how they are passed on the ABI level, but all this is implementation specific. Generally assume that the Result is in an invalid state.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: converting C++ over laz, issues with template operators conversion
« Reply #3 on: February 25, 2021, 08:54:22 am »
I wanted to let everyone know that this code fails with 3.2.0 compiler.. It forgets to insert the object reference when inlining ..

so this is an inline bug and without inline working this fix for classes isn't going to work..

No, this is not a bug. You're abusing implementation details and we give no guarantee for them to stay the same across versions. Even optimizations in 3.0.4 might result in your code no longer working.

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: converting C++ over laz, issues with template operators conversion
« Reply #4 on: February 26, 2021, 02:49:13 am »
I am sorry to disappoint you but yes, its a bug and I say that because it seems we try to be Delphi compliant ..
...
Like I said, this works perfectly fine with Delphi and 3.0.4 down..

I can't be the only one that has done code this way..

I don't think it is fair to call something a bug when the behavior is not specifically defined, or an actual feature, but the exploitation of a particular compiler implementation.

Sure, it works on certain platforms, but that is not "by design" but simply a by product of not doing it differently.
-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: converting C++ over laz, issues with template operators conversion
« Reply #5 on: February 26, 2021, 09:24:59 am »
I am sorry to disappoint you but yes, its a bug and I say that because it seems we try to be Delphi compliant ..

Here is a more simplified chuck of code that breaks with 3.2.0 and maybe upwards..

This all works fine with 3.0.4 and a few down that I have used.

 and to top it off, it also works in DELPHI  and has for years..

So? It's still using undefined behaviour. That can be very nicely seen if the inline is disabled:

Code: Pascal  [Select][+][-]
  1. program tinline;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. type
  9.   TForm1 = class
  10.   private
  11.     fCaption: String;
  12.     function GetCaption: String;
  13.     procedure SetCaption(const aValue: String);
  14.   published
  15.     property Caption: String read GetCaption write SetCaption;
  16.   end;
  17.  
  18. Procedure Ox(A:TForm1;Value:Integer);
  19. Begin
  20.  A.Caption := value.Tostring;
  21. End;
  22. operator := (R:Integer):Tform1;{inline;}
  23. Begin
  24.  Ox(Result,R);
  25. end;
  26.  
  27. var
  28.   Form1: TForm1;
  29.  
  30. { TForm1 }
  31.  
  32. function TForm1.GetCaption: String;
  33. begin
  34.   Result := fCaption;
  35. end;
  36.  
  37. procedure TForm1.SetCaption(const aValue: String);
  38. begin
  39.   fCaption := aValue;
  40. end;
  41.  
  42. begin
  43.   Form1 := TForm1.Create;
  44.   try
  45.     Form1 := 1;
  46.   finally
  47.     Form1.Free;
  48.   end;
  49. end.

The generated assembly code on i386-win32 looks like this for the assignment operator:

Code: ASM  [Select][+][-]
  1. .section .text.n_p$tinline_$$_assign$longint$$tform1,"x"
  2.         .balign 16,0x90
  3. .globl  P$TINLINE_$$_assign$LONGINT$$TFORM1
  4. P$TINLINE_$$_assign$LONGINT$$TFORM1:
  5. # [23] Begin
  6.         pushl   %ebp
  7.         movl    %esp,%ebp
  8.         leal    -8(%esp),%esp
  9. # Var R located at ebp-4, size=OS_S32
  10. # Var $result located at ebp-8, size=OS_32
  11.         movl    %eax,-4(%ebp)
  12. # [24] Ox(Result,R);
  13.         movl    -4(%ebp),%edx
  14.         movl    -8(%ebp),%eax
  15.         call    P$TINLINE_$$_OX$TFORM1$LONGINT
  16. # [25] end;
  17.         movl    -8(%ebp),%eax
  18.         movl    %ebp,%esp
  19.         popl    %ebp
  20.         ret

Here -8(%ebp) contains the Result value and as you can see it is not initialized in any way, thus Ox will access garbage. Now inlining has the restriction of not changing the behaviour of the code. Thus FPC 3.2.0 behaves correctly here. FPC 3.0.4 generates nearly identical code here if inlining is disabled.

That it behaves differently with active inlining on 3.0.4 or even Delphi is no reason that the behaviour of these is correct only that their code generators happen to generate the code in a way this works. This could behave totally different on a different platform, with different optimizations or e.g. on a LLVM-based backend which is known for aggressive optimizations (especially when undefined behaviour like this is involved).

Also depending on the code I can also get the same “incorrect” (from your PoV) behavior in FPC 3.0.4 which further shows that you're totally relying on circumstances that might change without any warning.

So, yeah, just don't do stuff like that.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: converting C++ over laz, issues with template operators conversion
« Reply #6 on: February 27, 2021, 01:53:06 pm »
This is absolutely a compiler bug

Either the code is correct, and then FPC should compile it to a working program

Or the code is not correct, and then FPC should not compile it at all, and abort the compilation with an error message.


In any case, what FPC does is wrong


Look what happens if you do it in Java:

Code: Java  [Select][+][-]
  1.  
  2. public class xy{
  3.  StringBuilder test(){
  4.    StringBuilder result;
  5.    result.append("foo");
  6.    return result;
  7.  }
  8. }

Code: Bash  [Select][+][-]
  1. $  javac xy.java
  2. xy.java:5: error: variable result might not have been initialized
  3.    result.append("foo");
  4.    ^
  5. 1 error
  6.  
  7.  

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: converting C++ over laz, issues with template operators conversion
« Reply #7 on: February 27, 2021, 03:12:03 pm »
Or the code is not correct, and then FPC should not compile it at all, and abort the compilation with an error message.

There is a near infinite amount of code that is incorrect, but that the compiler compiles.

And hey, look, the compiler does warn you:

Code: [Select]
PS C:\fpc\git> fpc -FEtestoutput .\fpctests\tinline.pp
Free Pascal Compiler version 3.2.0 [2020/07/07] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling .\fpctests\tinline.pp
tinline.pp(24,11) Warning: Function result variable does not seem to be initialized
Linking testoutput\tinline.exe
49 lines compiled, 0.3 sec, 72208 bytes code, 5236 bytes data
1 warning(s) issued

Yes a reference to the return is the problem and was solved using inline which stull works in Delphi of course and no longer in fpc.
Its like getting the newer model car only now there is no engine in it cuase its deemed unneeded
I stopped the converting of the c++ program and moving to Delphi now.

Fpc needs to fix this or give a reference return option.

There is nothing to fix.

FPK

  • Full Member
  • ***
  • Posts: 118
Re: converting C++ over laz, issues with template operators conversion
« Reply #8 on: February 27, 2021, 04:44:58 pm »

Fpc needs to fix this or give a reference return option.

Function name(....):var type;

Would be a good start.

... and then we get complains that

Function name(....):var type;
var
  v : type;
begin
   ...
   dosomething(v);
   ...
   result:=v;
end;

works in version 3.2.2134523462 but not in version 3.2.2134523463.

Extra work and still complaints. So not really an option.

FPK

  • Full Member
  • ***
  • Posts: 118
Re: converting C++ over laz, issues with template operators conversion
« Reply #9 on: February 27, 2021, 05:27:29 pm »
I don't want to harp on this but given it an option for  VAR return is a simple matter.

So you have a compiler patch ready?

Quote
So I am stuck at 3.0.4 and now moving my stuff over to Delphi for future work..

Delphi is always a good choice.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: converting C++ over laz, issues with template operators conversion
« Reply #10 on: February 27, 2021, 07:38:08 pm »

There is a near infinite amount of code that is incorrect, but that the compiler compiles.

Then FPC has infinitely many bugs.

At least they are countable

And I am only talking about compiled code that is incorrect with one version of FPC, but outputs the correct output with other versions of FPC

With reliable languages like Ada/SPARK or Wuffs such things do not happen


And hey, look, the compiler does warn you:

Code: [Select]
PS C:\fpc\git> fpc -FEtestoutput .\fpctests\tinline.pp
Free Pascal Compiler version 3.2.0 [2020/07/07] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling .\fpctests\tinline.pp
tinline.pp(24,11) Warning: Function result variable does not seem to be initialized
Linking testoutput\tinline.exe
49 lines compiled, 0.3 sec, 72208 bytes code, 5236 bytes data
1 warning(s) issued

But it is a warning, not an error. If there actually was something incorrect, it should give an error

Also with Lazarus warnings are hard to find

korba812

  • Sr. Member
  • ****
  • Posts: 390
Re: converting C++ over laz, issues with template operators conversion
« Reply #11 on: February 28, 2021, 12:42:18 am »
And hey, look, the compiler does warn you:

Code: [Select]
PS C:\fpc\git> fpc -FEtestoutput .\fpctests\tinline.pp
Free Pascal Compiler version 3.2.0 [2020/07/07] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling .\fpctests\tinline.pp
tinline.pp(24,11) Warning: Function result variable does not seem to be initialized
Linking testoutput\tinline.exe
49 lines compiled, 0.3 sec, 72208 bytes code, 5236 bytes data
1 warning(s) issued

But it is a warning, not an error. If there actually was something incorrect, it should give an error

Also with Lazarus warnings are hard to find
I don't think any compiler has been developed yet that can correctly guess what the programmer meant when writing the program.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: converting C++ over laz, issues with template operators conversion
« Reply #12 on: March 01, 2021, 01:17:58 pm »
And why do I need a compiler patch ? You only need to undo what is now broken.

Again, there is nothing broken in the compiler. Your code is broken. That it hasn't failed on Delphi does not mean that it isn't.

And FPK meant a patch regarding your reference result suggestion.

And I am only talking about compiled code that is incorrect with one version of FPC, but outputs the correct output with other versions of FPC

Code compiling in version A does not mean that it is correct code in version A. In this specific case it's abusing implementation details both in 3.0.4 and in Delphi (the former printing the below mentioned warning as well). I've even managed to get the example I posted to work "incorrectly" with 3.0.4 as well just by changing some settings.

And hey, look, the compiler does warn you:

Code: [Select]
PS C:\fpc\git> fpc -FEtestoutput .\fpctests\tinline.pp
Free Pascal Compiler version 3.2.0 [2020/07/07] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling .\fpctests\tinline.pp
tinline.pp(24,11) Warning: Function result variable does not seem to be initialized
Linking testoutput\tinline.exe
49 lines compiled, 0.3 sec, 72208 bytes code, 5236 bytes data
1 warning(s) issued

But it is a warning, not an error. If there actually was something incorrect, it should give an error

No, because the compiler does not know what the developer might have intended here. It simply points out that there might be something fishy there and if you ignore that and go your merry way then that's your problem.

now you can do this with Objects because they are static basically and Records but it seems the team has a rejection to doing this for Class pointers or even providing an option for a reference, so you use what works like I do..

Because that's how the ABI defines it (in this case "values of pointer size"). Adhering to the ABI is important for compatibility to other compilers, most importantly the platform's C compiler. This way one can for example return a class instance from the Pascal side as an opaque pointer type on the C side.

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: converting C++ over laz, issues with template operators conversion
« Reply #13 on: March 01, 2021, 04:19:26 pm »
Please no more. I can't take nonsense.
I tried to remove complete thread with no luck.

I moved it to Delphi, it all works there.
The only true wisdom is knowing you know nothing

korba812

  • Sr. Member
  • ****
  • Posts: 390
Re: converting C++ over laz, issues with template operators conversion
« Reply #14 on: March 05, 2021, 12:43:52 am »
First of all, maybe I don't fully understand the problem and have no idea how the compiler works, but ...
I imagine operator overloading as a function with the appropriate parameters and return value.
So
Code: Pascal  [Select][+][-]
  1. operator := (R: String): TForm1
will be translated to
Code: Pascal  [Select][+][-]
  1. function assignemt(R: String): TForm1
If possible, the inaccuracy introduced in Delphi could be formalized, but by introducing a different format for this situation - as a procedure with the additional var parameter.
Eg:
Code: Pascal  [Select][+][-]
  1. operator := (R: String; var L: TForm1)
will be translated to
Code: Pascal  [Select][+][-]
  1. procedure assignemt(R: String; var L: TForm1)
but then why shouldn't there be such a thing
Code: Pascal  [Select][+][-]
  1. operator := (var R: String; var L: TForm1)
  2. operator + (var R1, R2: Integer):TForm1

« Last Edit: March 05, 2021, 12:46:07 am by korba812 »

 

TinyPortal © 2005-2018