Recent

Author Topic: [SOLVED] functions with same return record-type share a record(?)  (Read 5527 times)

MMarie

  • New Member
  • *
  • Posts: 37
  • Right, lets bodge this pisspot
    • Homepage
After working on a project this evening I've realised that i'm relying on the fact that multiple of my functions which call into oneanother share the same record as a result?

e.g.
Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = record
  3.     {...}
  4.     bar: String;
  5.   end;
  6.  
  7. function A: TFoo;
  8. begin
  9.   A.bar := A.bar + ' bar';
  10. end;
  11.  
  12. function B: TFoo;
  13. begin
  14.   B.bar := 'foo'
  15.   B := A;
  16.   writeln(B.bar);
  17. end;
  18.  

when calling B, it would output "foo bar". My question here is: is this intended behaviour, on which I can rely? Are there any caveats when relying on this?
« Last Edit: May 23, 2024, 07:48:51 am by MMarie »
i use arch btw

Fibonacci

  • Hero Member
  • *****
  • Posts: 612
  • Internal Error Hunter
Re: functions with same return record-type share a record(?)
« Reply #1 on: May 19, 2024, 03:08:18 am »
That is an invalid memory access. You must initialize the record with default values or simply call FillChar(result, SizeOf(result), 0), or there will be garbage in the returned record, you absolutely cannot rely on this behavior.

Thaddy

  • Hero Member
  • *****
  • Posts: 16190
  • Censorship about opinions does not belong here.
Re: functions with same return record-type share a record(?)
« Reply #2 on: May 19, 2024, 04:07:32 am »
Indeed, that gives unpredicable behavior. Better is:
Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = record
  3.     {...}
  4.     bar: String;
  5.   end;
  6.  
  7. function A: TFoo;
  8. begin
  9.   A:=Default(TFoo);
  10.   A.bar := A.bar + ' bar';
  11. end;
  12.  
  13. function B: TFoo;
  14. begin
  15.   B:=Default(TFoo);
  16.   B.bar := 'foo'
  17.   B := A;
  18.   writeln(B.bar);
  19. end;

More in general you can also use a management operator to make sure a record is always properly initialized. And you can use "Result" to distinguish between function result and the function itself. Your syntax is a bit old school, but valid pascal.
 
« Last Edit: May 19, 2024, 06:01:23 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Thaddy

  • Hero Member
  • *****
  • Posts: 16190
  • Censorship about opinions does not belong here.
Re: functions with same return record-type share a record(?)
« Reply #3 on: May 19, 2024, 07:12:25 am »
Here's a more modern approach, but note your code is valid and basically this is just about notational differences that can improve readability:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$modeswitch advancedrecords}
  2. type
  3.   TFoo = record
  4.     bar: String;
  5.     class operator Initialize(var Value:TFoo);
  6.   end;
  7.  
  8. { called automatically, once per instance }
  9. class operator TFoo.Initialize(var Value:TFoo);
  10. begin
  11.    value := Default(TFoo);
  12. end;
  13.  
  14. function A: TFoo;
  15. begin
  16.   Result.bar := Result.bar + ' bar';
  17. end;
  18.  
  19. function B: TFoo;
  20. begin
  21.   Result := A;
  22. end;
  23.  
  24. begin
  25.   writeln(a.bar);
  26.   writeln(b.bar);
  27.   writeln(a.bar);
  28.   writeln(b.bar);
  29.   writeln(a.bar);
  30.   writeln(b.bar);
  31. end.

You can ignore the compiler warnings, because the record is always initialized, stack or heap allocated.
You can also see that there is no record sharing, but record copying.
« Last Edit: May 19, 2024, 07:58:13 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

dbannon

  • Hero Member
  • *****
  • Posts: 3156
    • tomboy-ng, a rewrite of the classic Tomboy
Re: functions with same return record-type share a record(?)
« Reply #4 on: May 19, 2024, 08:03:51 am »
Yes, the OP's code was definitely wrong. But I am intensely puzzled as to how it worked ?  I just tried it, and, again, it works.

In function A, the result.bar contains 'foo', at the start of the function, the only way it can get that information is from functions B's result.bar. Just looking at the code, I would have said function A's result.bar is just as likely to contain the Complete Works of Shakespeare as "foo".

Until the assignment happens at the end of function A, there is no connection between the two result variables. Is there ?

Davo

EDIT: No, I see, a function uses the variable its going to write to as its result variable. Wow, I did not realise that .....
« Last Edit: May 19, 2024, 08:08:52 am by dbannon »
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Thaddy

  • Hero Member
  • *****
  • Posts: 16190
  • Censorship about opinions does not belong here.
Re: functions with same return record-type share a record(?)
« Reply #5 on: May 19, 2024, 08:16:32 am »
It is not that strange that it works, because the record is allocated on the heap. Problems only arise if allocated on the stack.
If I smell bad code it usually is bad code and that includes my own code.

Thaddy

  • Hero Member
  • *****
  • Posts: 16190
  • Censorship about opinions does not belong here.
Re: functions with same return record-type share a record(?)
« Reply #6 on: May 19, 2024, 10:57:01 am »
Yes, the OP's code was definitely wrong.
The original code is NOT wrong, Davo, but it does not represent his intention:
Without initialization, it only goes wrong when called from inside of a procedure or function.
Otherwise it is heap memory and heap memory is initialized.
This archaic old man can still read archaic syntax.
Problems only occur when you nest those calls inside a method, procedure or function, because that is stack memory and stack memory is undetermined.
And before you start complaining, result variables have of course outer scope, not inner scope. Think.
« Last Edit: May 19, 2024, 11:08:18 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

simone

  • Hero Member
  • *****
  • Posts: 626
Re: functions with same return record-type share a record(?)
« Reply #7 on: May 19, 2024, 12:21:23 pm »
Just out of curiosity: is the new feature of record management operators documented in the language reference guide?

I only found this wiki: https://wiki.freepascal.org/management_operators

Thanks.
« Last Edit: May 19, 2024, 12:42:42 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Thaddy

  • Hero Member
  • *****
  • Posts: 16190
  • Censorship about opinions does not belong here.
Re: functions with same return record-type share a record(?)
« Reply #8 on: May 19, 2024, 12:55:13 pm »
Yes. It is.
« Last Edit: May 19, 2024, 01:03:17 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

alpine

  • Hero Member
  • *****
  • Posts: 1302
Re: functions with same return record-type share a record(?)
« Reply #9 on: May 19, 2024, 01:24:23 pm »
It is not that strange that it works, because the record is allocated on the heap. Problems only arise if allocated on the stack.
IMO the heap is not involved at all. The OP example works because it has just one field and,  by coincidence, A reuses result variable of B as its own result. In other scenarios it just may not work properly.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 8035
Re: functions with same return record-type share a record(?)
« Reply #10 on: May 19, 2024, 01:55:03 pm »
IMO the heap is not involved at all. The OP example works because it has just one field and,  by coincidence, A reuses result variable of B as its own result. In other scenarios it just may not work properly.

I admit to not understanding why those functions aren't going recursive.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

simone

  • Hero Member
  • *****
  • Posts: 626
Re: functions with same return record-type share a record(?)
« Reply #11 on: May 19, 2024, 03:19:33 pm »
Yes. It is.

I'm sorry, but I don't think so. Just as the free standing (i.e. outside the classes) generic procedures / functions and other more recent features are not documented in the language reference guide. If I'm wrong, I apologize and ask you in which section of the guide they are described.
« Last Edit: May 19, 2024, 03:27:52 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

alpine

  • Hero Member
  • *****
  • Posts: 1302
Re: functions with same return record-type share a record(?)
« Reply #12 on: May 19, 2024, 03:30:07 pm »
I admit to not understanding why those functions aren't going recursive.
Also a good point.

Isn't it that the Result variable was introduced to solve?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: functions with same return record-type share a record(?)
« Reply #13 on: May 19, 2024, 03:34:13 pm »
That looks perfectly valid code.

A needs a return record so it's using B, and since B gets defined beforehand, it already has the initial value.
The only true wisdom is knowing you know nothing

Fibonacci

  • Hero Member
  • *****
  • Posts: 612
  • Internal Error Hunter
Re: functions with same return record-type share a record(?)
« Reply #14 on: May 19, 2024, 04:24:04 pm »
That looks perfectly valid code.

A needs a return record so it's using B, and since B gets defined beforehand, it already has the initial value.

Nah. Its invalid, its unpredictable. OPs code prints "foo bar", but with this line 16 below that does nothing it prints " bar".

Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = record
  3.     bar: String;
  4.   end;
  5.  
  6. function A: TFoo;
  7. begin
  8.   A.bar := A.bar + ' bar';
  9. end;
  10.  
  11. function B: TFoo;
  12. begin
  13.   B.bar := 'foo';
  14.   B := A;
  15.   writeln(B.bar);
  16.   if dword(@B) <> 0 then;
  17. end;
  18.  
  19. begin
  20.   b;
  21.   readln;
  22. end.
« Last Edit: May 19, 2024, 04:27:27 pm by Fibonacci »

 

TinyPortal © 2005-2018