Forum > Beginners

[Res.] Why is enumerating a dynamic array different from accessing it by Index?

(1/3) > >>

Nimral:
I found out (the hard way ... wasted long hours on this) that the following code snippets produce different results:

These are the key parts showing the problem, a complete source is attached as well.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type  PPayload = ^TPayload;   TPayload = record    ID: integer;    Name: string[50];  end;  TArrPayload = array of TPayload; var  ArrPayload: TArrPayload;  // ....................    // initalize the nodes   for i := low(ArrPayload) to high(ArrPayload) do  begin    VirtualStringTree1.AddChild(nil,@ArrPayload[i]);  end;   for rec in ArrPayload do     VirtualStringTree1.AddChild(nil, @rec);  
VirtualStringTree.AddChild expects a pointer to data. The for ... in loop does deliver an invalid address, the for loop with integer index counter works correctly. Whatever rec contains, it is not, like I expected, a pointer to a record from the array.

Anyone with deeper insight into FPC who can explain this?

Thnx, Armin.

Enclosed you find a little demo project to show the problem in context of a program, just in case anyone wants to see why I came to the conclusion that there must be a difference. The first 5 nodes are passed correctly, the other five contain a garbage address, and it's obviously 5 times the same address, since the garbage is always the same.

Armin.

ASerge:

--- Quote from: Nimral on May 06, 2021, 09:44:16 pm ---I found out (the hard way ... wasted long hours on this) that the following code snippets produce different results:

--- End quote ---

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---for rec in ArrPayload doHere, rec is a local copy of the actual data. Saving the address of this variable is pointless.

Nimral:
I can assign like this, can't I?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---for rec in ArrPayload do   rec.Name := 'Bla'; 
and this will modify the records in ArrPayload, right? So it *looks* like rec is an equivalent to ArrPayload[ i ], but it isn't? If it is not, what then is rec? Would there have been a way to pass the address of every record, like intended, using the for ... in enumeration mechanism?

Armin.

Remy Lebeau:

--- Quote from: Nimral on May 06, 2021, 09:44:16 pm ---The for ... in loop does deliver an invalid address

--- End quote ---

No, it delivers a valid record, you are just taking the address of that record and expecting that address to outlive the actual lifetime of the record, which it doesn't.


--- Quote from: Nimral on May 06, 2021, 09:44:16 pm ---Whatever rec contains, it is not, like I expected, a pointer to a record from the array.

--- End quote ---

It is not a pointer to a record, no.  It is an actual instance of a record, that has been copied from the array.


--- Quote from: Nimral on May 06, 2021, 09:44:16 pm ---The first 5 nodes are passed correctly, the other five contain a garbage address, and it's obviously 5 times the same address, since the garbage is always the same.

--- End quote ---

It is not garbage. The for..in loop is simply generating a hidden variable for its enumeration to use, and you are storing the address of that variable 5 times.  The variable doesn't exist anymore when the loop is done.


--- Quote from: Nimral on May 06, 2021, 09:57:33 pm ---I can assign like this, can't I?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---for rec in ArrPayload do   rec.Name := 'Bla';
and this will modify the records in ArrPayload, right?

--- End quote ---

No, it will not, because ArrPayload is an array of records, so rec is a copy of each record in the array.

Now, if you had an array of object pointers, that would be a different story...


--- Quote from: Nimral on May 06, 2021, 09:57:33 pm ---So it *looks* like rec is an equivalent to ArrPayload[ i ], but it isn't? If it is not, what then is rec?

--- End quote ---

Have you read the documentation yet?

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

Essentially, your for..in loop is basically the same as doing this:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---var  rec: TPayload;  i: Integer; for i := Low(ArrPayload) to High(ArrPayload) dobegin  rec := ArrPayload[i]; // <-- COPY MADE HERE!  rec.Name := 'Bla'; // <-- MODIFYING THE COPY, NOT THE ORIGINAL!  VirtualStringTree1.AddChild(nil, @rec); // <-- STORING THE ADDRESS OF THE COPY!end; // <-- COPY NOT ASSIGNED BACK TO ARRAY!

Nimral:
Thanks Remy, for the brief explanation.

I did, however, assume (wrongly) then through the loop variable (rec) I get a "handle" to the current element of the enumerated structure, but it seems that the designers od Pascal had other ideas.

What is the purpose of introducing a local copy then? It doesn't make much sense to me?

And, yes, I flipped through the man pages, I found no information regarding this "local copy". It says (last sentence) that I may not change the loop variable (like it is forbidden to change the counter of a for ... to loop), but it doesn't say anything that it is also forbidden or at least pointless to change the data structure rec points to.

Anyway, languages are defined the way they are, and not like it may seem logical to someone like me.

Armin.

Navigation

[0] Message Index

[#] Next page

Go to full version