Recent

Author Topic: operators overloads working only one way?  (Read 799 times)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5649
  • Compiler Developer
Re: operators overloads working only one way?
« Reply #15 on: September 04, 2024, 08:07:49 pm »
What em I doing wrong here?

There is no operator in your code that converts a TByte to a TMemoryStream. The assignment operator you expect to work only applies to assignments to TStream.

Also as others said your implementation of the operator overload itself is wrong. It might work by pure chance depending on the involved platform and optimizations settings, but it's definitely not guaranteed, because it's simply wrong code.

jamie

  • Hero Member
  • *****
  • Posts: 6529
Re: operators overloads working only one way?
« Reply #16 on: September 04, 2024, 08:18:44 pm »
I have the default settings lazarus sets.

Anyways,

 I found that if I use a
Code: Pascal  [Select][+][-]
  1. Var
  2.  S:STream;
  3.  B:Byte;
  4. Begin
  5.  S:= TMemoryStream.Create;
  6.  B := Byte(10);
  7.  S.Position := 0;
  8.   B:= S;
  9.   Caption := B.ToString;
  10.   S.Free;
  11.  End;
  12.  

Seems to work just fine! thank you.
The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 5649
  • Compiler Developer
Re: operators overloads working only one way?
« Reply #17 on: September 04, 2024, 09:27:06 pm »
Seems to work just fine! thank you.

You use the right word: it seems to work, simply because the instance value from the TMemoryStream.Create is still located on the no longer used stack when the assignment operator is called. If you instead insert a function that uses that area then your code will fail:

Code: Pascal  [Select][+][-]
  1. program tcnv;
  2.  
  3. {$mode objfpc}
  4.  
  5. uses
  6.   Classes;
  7.  
  8. operator :=(aArg: Byte): TStream;
  9. begin
  10.   Result.Write(aArg, SizeOf(aArg));
  11. end;
  12.  
  13. operator :=(aArg: TStream): Byte;
  14. begin
  15.   aArg.Read(Result, SizeOf(Result));
  16. end;
  17.  
  18. procedure OverwriteStack(aArg1, aArg2: Int64);
  19. var
  20.   a, b: Int64;
  21. begin
  22.   a := aArg1;
  23.   b := aArg2;
  24.   Writeln(a, b);
  25. end;
  26.  
  27. var
  28.   s: TStream;
  29.   b: Byte;
  30. begin
  31.   s := TMemoryStream.Create;
  32.   OverwriteStack(0, 0);
  33.   s := Byte(42);
  34.   s.Position := 0;
  35.   b := s;
  36.   Writeln(b);
  37.   s.Free;
  38. end.

TRon

  • Hero Member
  • *****
  • Posts: 3163
Re: operators overloads working only one way?
« Reply #18 on: September 04, 2024, 09:33:38 pm »
As PascalDragon wrote,

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$mode objfpc}{$h+}
  4. {.$define cast}
  5.  
  6. uses
  7.   classes;
  8.  
  9. operator :=(S: TMemoryStream) B :Byte;
  10. begin
  11.   writeln('S->B, address of S = $', HexStr(S));
  12.   S.Read(B,1);
  13. end;
  14.  
  15. operator :=(B:byte) S: TMemoryStream;
  16. begin
  17.    writeln('B->S, address of S = $', HexStr(S));
  18.    S.Position := 0;
  19.    S.Write(B,1);
  20. end;
  21.  
  22. var
  23.   B:Byte;
  24.   {$ifdef cast}
  25.   S:TStream;
  26.   {$else}
  27.   MS:TMemoryStream;
  28.   {$endif}
  29. begin
  30.   {$ifndef cast}
  31.   MS:= TMemoryStream.Create;
  32.   writeln('address of S = $', HexStr(MS));
  33.   MS := B; // compiles if operator is defined using exact class-name. There isn't an operator for B->TStream unless it is created, or cast see below
  34.   B := MS;
  35.   MS.Free;
  36.   {$else}
  37.   S:= TMemoryStream.Create;
  38.   writeln('address of S = $', HexStr(S));
  39.   TMemoryStream(S) := B; // compiles, if cast correctly.
  40.   B := TMemoryStream(S);
  41.   S.Free;
  42.   {$endif}
  43. end.

linux x86_64:
Code: Bash  [Select][+][-]
  1. $ ./test
  2. ./test
  3. address of S = $00007F283D695E00
  4. B->S, address of S = $00000000004D83F8
  5. An unhandled exception occurred at $00000000004011B3:
  6. EAccessViolation: Access violation
  7.   $00000000004011B3  assign,  line 18 of test.pas
  8.   $0000000000401296  main,  line 33 of test.pas
  9.  
  10. Heap dump by heaptrc unit of /media/ramdisk-8gb/fpc/test
  11. 222 memory blocks allocated : 48050/48072
  12. 218 memory blocks freed     : 47818/47840
  13. 4 unfreed memory blocks : 232
  14. True heap size : 196608
  15. True free heap : 195488
  16. Should be : 195608
  17. Call trace for block $00007F283D67D100 size 128
  18.   $0000000000414241
  19.   $0000000000401296  main,  line 33 of test.pas
  20. Call trace for block $00007F283D696000 size 40
  21.   $0000000000414241
  22.   $0000000000401296  main,  line 33 of test.pas
  23. Call trace for block $00007F283D695F00 size 24
  24.   $0000000000401296  main,  line 33 of test.pas
  25. Call trace for block $00007F283D695E00 size 40
  26.  

edit: line-numbers were off, re-posted source and output so that they (hopefully) match.
« Last Edit: September 04, 2024, 10:04:53 pm by TRon »
All software is open source (as long as you can read assembler)

jamie

  • Hero Member
  • *****
  • Posts: 6529
Re: operators overloads working only one way?
« Reply #19 on: September 04, 2024, 11:02:09 pm »
Ok, I'll go a different direction with this.

The problem here, and I have asked for this before, is we need a REFENCE option for the return, which C++ has

For larger than items that can't fit in registers, the compiler generates a reference to it. with the reference you have a direct route to the return item so you can directly interact on it.

For example.

Code: Pascal  [Select][+][-]
  1. operator := (A:Byte) Var :TStream;
  2. Begin
  3.  Result.xxxxx;// now is guaranteed to work.
  4. End;
  5.  

Something to think about if you want to get ahead of the other guys!  :o
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018