CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
More array issues....

 



chrislas
Novice

Aug 2, 2013, 5:23 AM

Post #1 of 10 (1196 views)
More array issues.... Can't Post

Unfortunately, I am still struggeling a bit with getting my head around arrays and array-refs...

I am ending up with empty arrays in places I thought I would not. Here is a simple example:


Code
sub mainloop{ 
my @array;
for (my $i=0;$i<10;$i++){
do_something(\@array);
}
print "Last array element is $#array\n";
}

sub do_something{
my $arrayref=shift;
my @array=@{ $arrayref };
# I am guessing the problem is the line above? Am I creating a new copy of the array?
do_something_else(\@array);
}

sub do_something_else{
my $arrayref=shift;
my @array=@{ $arrayref };
push @array, { number => 1};
}


I was expecting an output of
Last array element is 9
But in stead it is -1, so empty.

Is the problem that I am actually pushing items onto a copy of my array, so no items are added to the original one declared in the mainloop?
If so, what would be the correct way of doing this?
Would I simply change the do_something routine to just pass on the same ref as it got in, like this:


Code
   do_something_else($arrayref);


And then in the do_something_else subroutine, I would do something like


Code
   push @{ $arrayref }, { number => 1 };


Or am I barking up the wrong tree here?

Any enlightenment would be greatly appreciated!


Zhris
Enthusiast

Aug 2, 2013, 6:32 AM

Post #2 of 10 (1180 views)
Re: [chrislas] More array issues.... [In reply to] Can't Post

Hi,

As you stated, the problem is indeed that you are pushing elements onto copies of your array, and your suggested fix would work. Looks like you have your issue covered.

Just to clarify in case you didn't realise, $#array will return the last elements index / subscript. If you had 1 element in your array, it would return 0. Since you have 0 elements in your array it logically returns -1.

Regards,

Chris


Code
use strict; 
use warnings;

mainloop();

sub mainloop{
my @array;
for (my $i=0;$i<10;$i++){
do_something(\@array);
}
print "Last array element is $#array\n";
}

sub do_something{
do_something_else($_[0]);
}

sub do_something_else{
push @{$_[0]}, { number => 1};
}



FishMonger
Veteran / Moderator

Aug 2, 2013, 6:51 AM

Post #3 of 10 (1175 views)
Re: [chrislas] More array issues.... [In reply to] Can't Post

Chris has answered your question, but there is a bigger more important question you should be asking yourself. Why would you want to have a var altered by any number of downstream child subs?

Action at a distance especially in a chain like that is a really bad spaghetti coding practice and will lead to buggy code that is very difficult to troubleshoot.


chrislas
Novice

Aug 2, 2013, 7:02 AM

Post #4 of 10 (1172 views)
Re: [FishMonger] More array issues.... [In reply to] Can't Post

Fair question, Fishmonger!
And maybe you would approach the task differently:

This is a game-related "combat-simulator", and the var, or array, in question, is a list of all ships in the combat.
I have different subroutines for things like target-selection, weaponsfire, AI-descision-making that all alters different data in the array.
So the target-selection will affect the targeting-data of the ships, and the AI-descision-routines will modify other things etc etc etc.

I can understand that someone will hint at me getting good at OO at this point, but I don't have the time now.

But what kind of approach would you recommend for such a setup?


chrislas
Novice

Aug 2, 2013, 7:06 AM

Post #5 of 10 (1169 views)
Re: [Zhris] More array issues.... [In reply to] Can't Post


In Reply To
Just to clarify in case you didn't realise, $#array will return the last elements index / subscript. If you had 1 element in your array, it would return 0. Since you have 0 elements in your array it logically returns -1.


I know ;)
The surprise was not the -1 as such, but the lack of 9 :)

I WAS surprised the other day when I discovered that
scalar @{ $array[$i]{data} }
returned 0 in stead of -1, but that's just me :)


Zhris
Enthusiast

Aug 2, 2013, 7:13 AM

Post #6 of 10 (1168 views)
Re: [chrislas] More array issues.... [In reply to] Can't Post

Hi

Your code could be simplified to i.e.:


Code
push@array,{number=>1}for(0..9); 
print "Last array element is $#array\n";


Although I have deliberately compacted it, it is by far more maintainble and easier on the eyes.

I assume that your code was just an example to represent the problem of passing array refs, and not your "real world" code.

Chris


Zhris
Enthusiast

Aug 2, 2013, 7:16 AM

Post #7 of 10 (1167 views)
Re: [chrislas] More array issues.... [In reply to] Can't Post


Code
my @array = ( 1 ); 

print scalar @array . "\n"; # returns the number of elements in the array

#print @array . "\n"; # does the same as above
my $count = @array;
print $count . "\n";


print $#array . "\n"; # returns the last elements subscript


output:

Code
1 
1
0


Edit: my mistake. Never do "print @array", since print is a function and will take each element of @array as arguments. Just so happened I used 1 for an array element.

Chris


(This post was edited by Zhris on Aug 2, 2013, 7:28 AM)


BillKSmith
Veteran

Aug 2, 2013, 7:19 AM

Post #8 of 10 (1165 views)
Re: [chrislas] More array issues.... [In reply to] Can't Post


Am I creating a new copy of the array?

Quote

The short answer is "YES!"

Your code indicates that you have a bigger problem with perl's lexical variables and their scope than you do with references.

There is no problem in mainloop. You create an empty array and pass a reference to "do_something".

In "do_something", you shift that reference into a new scalar variable called "$arrayref". So far so good. Now the command "my @array" creates a new array which will exist until you reach the end of "do_something" block. You then give it the value (currently empty) of the @array in mainloop. You then pass a reference to this array to "do_something_else". Again, you create a new variable called "$arrayref" and shift the new reference into it. You now create a new lexical array and assign it the value of the @array from do_something.

You push a reference to a hash into that array and return
from "do_something_else." As soon as you return, the copy of the array which contains the hash goes out of existence! You now return from "do_something". Now its copy of @array goes out of existence also.

Then you repeat the sequence nine more times and print the original @array (which is still empty).


Refer to the "Private Variables" section of perlsub.

Code
perldoc perlsub


Note that the variables $array_ref are created and destroyed in exactly the same way as the @array variables. In former case, it is exactly whay you want.

I belileve that this is what you intend:

Code
use strict; 
use warnings;
use Data::Dumper;

mainloop();

sub mainloop {
my @array;
for ( my $i = 0; $i < 10; $i++ ) { do_something( \@array ); }
print "Last array element is $#array\n";
print Dumper \@array;
}

sub do_something {
my $arrayref = shift;
#####my @array = @{$arrayref};
# I am guessing the problem is the line above?
# Am I creating a new copy of the array?
do_something_else($arrayref);
}

sub do_something_else {
my $arrayref = shift;
#####my @array = @{$arrayref};
push @{$arrayref}, { number => 1 };
}

Good Luck,
Bill


chrislas
Novice

Aug 2, 2013, 7:20 AM

Post #9 of 10 (1164 views)
Re: [Zhris] More array issues.... [In reply to] Can't Post


In Reply To
I assume that your code was just an example to represent the problem of passing array refs, and not your "real world" code.
Chris


Very much so, but thank you :)


FishMonger
Veteran / Moderator

Aug 2, 2013, 8:05 AM

Post #10 of 10 (1148 views)
Re: [chrislas] More array issues.... [In reply to] Can't Post


Quote
I can understand that someone will hint at me getting good at OO at this point

Yes, that would be best.


Quote
But what kind of approach would you recommend for such a setup?

If you're not ready to go the OO route, then the next best approach would be to use a more complex hash data structure. Without detailed info on your app, I can't say how complex that hash should be.

I'd also keep the action at a distance issue to a minimum, which means I would only go 1 level. If you need to go down multiple child subs, then I'd make use of return statements and direct assignments.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives