Recent

Author Topic: Assigning result of a function of type array  (Read 893 times)

simsee

  • Full Member
  • ***
  • Posts: 189
Assigning result of a function of type array
« on: September 13, 2024, 11:56:54 pm »
I have an embarrassing doubt, because I'm not a beginner.

Given that the assignment of a static/dynamic array to another determines only an assignment of the pointer to it, not of the elements, to assign which you need the copy function, when you assign the result of a function whose result type is a static/dynamic array, you have to use copy?

For example:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. type
  3.   TArr=array of byte;
  4.  
  5.   function Func:TArr;
  6.   begin
  7.     SetLength(Result,1);
  8.     Result[0]:=1;
  9.   end;
  10.  
  11. var
  12.   Arr : TArr;
  13.  
  14. begin
  15.   Arr:=Func; //or Arr:=Copy(Func); ???
  16. end.  

jamie

  • Hero Member
  • *****
  • Posts: 6556
Re: Assigning result of a function of type array
« Reply #1 on: September 14, 2024, 12:41:20 am »
The function returns the array, which is a pointer to a managed type, it does not copy it.

Unless there is something else you are thinking of?

The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 15646
  • Censorship about opinions does not belong here.
Re: Assigning result of a function of type array
« Reply #2 on: September 14, 2024, 07:48:28 am »
If you intend to use the returned array in its own context you need a copy indeed.
Say you have an array  a and an array b then follows:
a:= b makes a pointer copy and refcount increases. if an element in b changes it also changes in a.
a:= copy(b,0,high(b)) makes a deep copy and now when b changes, a will not change


If I smell bad code it usually is bad code and that includes my own code.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7633
Re: Assigning result of a function of type array
« Reply #3 on: September 14, 2024, 08:31:27 am »
I had a related problem with (from memory) a const array parameter which turned out not to be.

If in doubt, make a copy.

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: 605
Re: Assigning result of a function of type array
« Reply #4 on: September 14, 2024, 09:45:49 am »
For deep copy of a whole array you can also use copy without index and count parameters, although this is not explicitly documented here https://www.freepascal.org/docs-html/rtl/system/copy.html regarding the omission of index. So, you can write:

Code: Pascal  [Select][+][-]
  1. A:=copy(B);

Anyway I think the op's question is about assigning a constant array (in that case result of a function).
« Last Edit: September 14, 2024, 10:04:41 am by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

simsee

  • Full Member
  • ***
  • Posts: 189
Re: Assigning result of a function of type array
« Reply #5 on: September 14, 2024, 10:03:21 am »
Yes, thank you, but my doubt is: when I have to assign a constant array is it necessary to use copy to have a deep copy?

MarkMLl

  • Hero Member
  • *****
  • Posts: 7633
Re: Assigning result of a function of type array
« Reply #6 on: September 14, 2024, 10:14:20 am »
Yes, thank you, but my doubt is: when I have to assign a constant array is it necessary to use copy to have a deep copy?

If you really do want it to be distinct, I believe so.

There's an uncomfortable (to me) echo of ALGOL-60's "call-by-name", which was generally considered to be a mistake.

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

Warfley

  • Hero Member
  • *****
  • Posts: 1581
Re: Assigning result of a function of type array
« Reply #7 on: September 14, 2024, 02:09:16 pm »
Static arrays are copy by value, dynamic arrays are reference counted copy by reference with lazy copy mechanism.

Basically while (unlike strings) you can edit arrays in place, changing the array value across multiple references, whenever you can SetLength it guarantees that the refcount will always be 1.
So best practice is to just assign the references and only if you really need a unique copy make it unique, e.g. with SetLength(arr, Length(arr))

In your example, because SetLength is called it's guaranteed to be a unique copy, so no need to do any copying afterwards.

Also note that if you use threading, arrays are not thread safe, so uniquify them for each thread

simone

  • Hero Member
  • *****
  • Posts: 605
Re: Assigning result of a function of type array
« Reply #8 on: September 14, 2024, 02:29:40 pm »
@Warfley: Nice explanation.

I have some doubts about the behavior of constant arrays. Consider the following example:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. var
  3.   A : array of integer;
  4. const
  5.   B : array of integer=(0,1);
  6. begin
  7.   A:=B;
  8.   A[0]:=-1;
  9.   writeln(A[0]);
  10.   writeln(B[0]);
  11.   readln;
  12. end.

Result is:

-1
-1


This is technically understandable (the pointers of A and B are the same, due to shallow copy performed by assignment), but B is a constant array and should not be modifiable.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Thaddy

  • Hero Member
  • *****
  • Posts: 15646
  • Censorship about opinions does not belong here.
Re: Assigning result of a function of type array
« Reply #9 on: September 14, 2024, 03:35:07 pm »
This is only the case in {$J+} state. In {$J-} state you get a runtime error.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$J-}  // crashes
  2. var
  3.   A : array of integer;
  4. const
  5.   B : array of integer=(0,1);
  6. begin
  7.   A:=B;
  8.   A[0]:=-1;  // crashes here in {$J-} state. A points to read-only memory from B.
  9.   writeln(A[0]);
  10.   writeln(B[0]);
  11.   readln;
  12. end.
If {$writeableconst off} or {$J-} the crash can be explained because assignment to an address in read-only space is not allowed. If they are in {$J+} state, the const is actually a global static var and that can legally be changed. The default is {$J+}
Note that a direct assignment to B in {$J-} generates a compile time error. The example generates a runtime error.
« Last Edit: September 14, 2024, 04:07:56 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Warfley

  • Hero Member
  • *****
  • Posts: 1581
Re: Assigning result of a function of type array
« Reply #10 on: September 14, 2024, 06:58:43 pm »
As thaddy nicely demonstrated, a typed const is not a constant but a writable const. An object with static lifetime but local scope, meaning a global variable only accessible to the function in which it is declared. It's very useful but syntactically confusing.

If you want real consts you need to set the writableconst or J Compiler Switch off

Thaddy

  • Hero Member
  • *****
  • Posts: 15646
  • Censorship about opinions does not belong here.
Re: Assigning result of a function of type array
« Reply #11 on: September 15, 2024, 07:41:50 am »
Two other remarks:
Real consts are if possible directly substituted by the compiler, so not stored at all, or complex consts stored in the .rodata section.
Typed consts in {$writeableconst on mode} are stored as global vars with local scope. Warfley added more explanation.
Typed consts in {$writeableconst off} mode are always stored in the .rodata section.
.rodata is read-only data.
If I smell bad code it usually is bad code and that includes my own code.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5672
  • Compiler Developer
Re: Assigning result of a function of type array
« Reply #12 on: September 15, 2024, 09:14:41 pm »
Typed consts in {$writeableconst off} mode are always stored in the .rodata section.
.rodata is read-only data.

This depends on the used assembler. If the GNU assembler is used then on some platforms it will be .rodata, but on others it will be .data due to issues with relocations (see comment in TGNUAssembler.sectionname() in compiler/aggas.pas).

Thaddy

  • Hero Member
  • *****
  • Posts: 15646
  • Censorship about opinions does not belong here.
Re: Assigning result of a function of type array
« Reply #13 on: September 16, 2024, 05:41:03 pm »
That is an interesting thing I did not know about yet. But at least it is the intention that it is stored in a read-only section. Thanks for that info.
I only tested windows 10/11 64 and linux 64 both on amd64.
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018