sub local variable changes global variable.

Hi all,

I am passin a two-dimensional array to a sub and when the sub returns, the original array has changed. Eventually I want to pass the array into a recursive sub, so I want to find a way to circumvent 
this behaviour. Notice how my global is "@a" and the sub local is "@b"
- Why is this happening
- How can I properly pass a two dimensional array to a sub, without the array in main changing?

Ideas anyone?

Here is the minimal script to reproduce my finding:
=============
#!/usr/bin/perl

use warnings;
use strict;

sub try {
         my @b = @_;
         $b[ 0 ][ 1 ] = "7";
         return 3;
}

my @a;
$a[ 0 ][ 1 ] = " ";

print "Before: " . $a[ 0 ][ 1 ] . "\n";
try( @a );
print "After:  " . $a[ 0 ][ 1 ] . "\n";

exit;
=============
What happens:
Before:
After:  7
=============
What I would expect:
Before:
After:  0
=============
0
jph4dotcom
10/15/2011 11:08:19 PM
perl.beginners 29378 articles. 3 followers. Follow

9 Replies
695 Views

Similar Articles

[PageSpeed] 24

On Sun, Oct 16, 2011 at 01:08:19AM +0200, JPH wrote:
> Hi all,
> 
> I am passin a two-dimensional array to a sub and when the sub

This is your main problem.  Perl doesn't have two-dimensional arrays.  What it
does have is arrays of array references which, if you squint, can be used as
two-dimensional arrays.  And this is what you have here.  Armed with this
knowledge, perhaps you can already see the problem and solution.

> returns, the original array has changed. Eventually I want to pass
> the array into a recursive sub, so I want to find a way to
> circumvent this behaviour. Notice how my global is "@a" and the sub
> local is "@b"
> - Why is this happening
> - How can I properly pass a two dimensional array to a sub, without the array in main changing?
> 
> Ideas anyone?

When call try(), (or more accurately, when you assign to @b) you are
performing a shallow copy of the array.  It seems that you really need a deep
copy.  You could either explicity write this yourself, or you could use
something such as dclone in Storable.

> Here is the minimal script to reproduce my finding:
> =============
> #!/usr/bin/perl
> 
> use warnings;
> use strict;
> 
> sub try {
>         my @b = @_;
>         $b[ 0 ][ 1 ] = "7";
>         return 3;
> }
> 
> my @a;
> $a[ 0 ][ 1 ] = " ";
> 
> print "Before: " . $a[ 0 ][ 1 ] . "\n";
> try( @a );
> print "After:  " . $a[ 0 ][ 1 ] . "\n";
> 
> exit;
> =============
> What happens:
> Before:
> After:  7
> =============
> What I would expect:
> Before:
> After:  0
> =============

-- 
Paul Johnson - paul@pjcj.net
http://www.pjcj.net
0
paul
10/15/2011 11:31:00 PM
On 16/10/2011 00:08, JPH wrote:
> Hi all,
>
> I am passin a two-dimensional array to a sub and when the sub returns,
> the original array has changed. Eventually I want to pass the array into
> a recursive sub, so I want to find a way to circumvent this behaviour.
> Notice how my global is "@a" and the sub local is "@b"
>
> - Why is this happening
> - How can I properly pass a two dimensional array to a sub, without the array in main changing?
>
> Ideas anyone?
>
> Here is the minimal script to reproduce my finding:
> =============
> #!/usr/bin/perl
>
> use warnings;
> use strict;
>
> sub try {
>          my @b = @_;
>          $b[ 0 ][ 1 ] = "7";
>          return 3;
> }
>
> my @a;
> $a[ 0 ][ 1 ] = " ";
>
> print "Before: " . $a[ 0 ][ 1 ] . "\n";
> try( @a );
> print "After:  " . $a[ 0 ][ 1 ] . "\n";
>
> exit;
> =============
> What happens:
> Before:
> After:  7
> =============
> What I would expect:
> Before:
> After:  0
> =============

Naming your variables just a and b is a bad idea - the name should
reflect what they contain. Also it is generally better to pass arrays
and hashes to subroutines by reference, but I will work with what you
have written so far as, depending on the problem you are solving, any
changes may be irrelevant.

Your "two-dimensional array" @a is an array of array references, so
calling the subroutine as

   try(@a);

in fact passes each row as a separate parameter, like this

   try($row0, $row1, $row2, $row3);

and since your subroutine starts with

   sub try {
     my @b = @_;
     :
   }

you are simply copying those array references into @b, like this

   my @b = ($row0, $row1, $row2, $row3);

so $a[0][1] is the same as $row0->[1] and so also $b[0][1], so by
changing one you are also changing the other. For the local array to be
independent of the one passed, you must duplicate all the rows,
replacing the first line of the subroutine with something like

   sub try {
     my @b;
     foreach my $row (@_) {
       push @b, [@$row];
     }
     :
   }


I think it is unlikely that your design is the best solution to your
problem, but since you say nothing of your requirements I cannot suggest
anything better. Depending on the size of your arrays and the level of
recursion you may easily absorb large amounts of memory.

I hope this helps,

Rob
0
rob
10/15/2011 11:44:02 PM
On 11-10-15 07:44 PM, Rob Dixon wrote:
>
>    sub try {
>      my @b;
>      foreach my $row (@_) {
>        push @b, [@$row];
>      }
>      :
>    }
>

Or you could use dclone() from Storable:

   use Storable qw( dclone );

   sub try {
     my @b = @{ dclone( \@_ ) };
     ...
   }

Storable is a standard module that is installed with Perl. For a list of 
all standard pragmatics and modules, see `perldoc perlmodlib`.


-- 
Just my 0.00000002 million dollars worth,
   Shawn

Confusion is the first step of understanding.

Programming is as much about organization and communication
as it is about coding.

The secret to great software:  Fail early & often.

Eliminate software piracy:  use only FLOSS.

"Make something worthwhile."  -- Dear Hunter
0
shawnhcorey
10/16/2011 2:05:08 AM
JPH wrote:
> Hi all,

Hello,

> I am passin a two-dimensional array to a sub and when the sub returns,
> the original array has changed.  Eventually I want to pass the array into
> a recursive sub, so I want to find a way to circumvent this behaviour.
> Notice how my global is "@a" and the sub local is "@b"
> - Why is this happening
> - How can I properly pass a two dimensional array to a sub, without the
> array in main changing?
>
> Ideas anyone?

Change your subroutine so that it does not modify the array values?


> Here is the minimal script to reproduce my finding:
> =============
> #!/usr/bin/perl
>
> use warnings;
> use strict;
>
> sub try {
> my @b = @_;
> $b[ 0 ][ 1 ] = "7";
> return 3;
> }
>
> my @a;
> $a[ 0 ][ 1 ] = " ";

Or more simply:

my @a = [ undef, " " ];


> print "Before: " . $a[ 0 ][ 1 ] . "\n";
> try( @a );
> print "After: " . $a[ 0 ][ 1 ] . "\n";
>
> exit;
> =============
> What happens:
> Before:
> After: 7
> =============
> What I would expect:
> Before:
> After: 0

If you originally assign " " to $a[ 0 ][ 1 ] why would you now expect it 
to contain 0?



John
-- 
Any intelligent fool can make things bigger and
more complex... It takes a touch of genius -
and a lot of courage to move in the opposite
direction.                   -- Albert Einstein
0
jwkrahn
10/16/2011 6:29:24 AM
You got me there, John. Indeed I do expect it to contain '  ' and not 0 like I stated.
> If you originally assign " " to $a[ 0 ][ 1 ] why would you now expect it to contain 0?
>
>
>
> John
0
jph4dotcom
10/16/2011 9:31:37 AM
Thanks! My script seems to work with dclone.

Though the (deep) recursion takes a lot of time ...
What is your opinion, would it pay off (in performance) when I rewrite the script in such a way that I do not use dclone, but string manipulation routines instead? So:
  - passing a single dimension array containing 16 elements with 16-character strings and doing substr()
  - instead of passing a 2 dimensional (16x16) array passing 1-character strings and doing dclone
Every pass I only change a single character, then I run some tests and so on.

On 10/16/2011 04:05 AM, Shawn H Corey wrote:
> On 11-10-15 07:44 PM, Rob Dixon wrote:
>>
>>    sub try {
>>      my @b;
>>      foreach my $row (@_) {
>>        push @b, [@$row];
>>      }
>>      :
>>    }
>>
>
> Or you could use dclone() from Storable:
>
>   use Storable qw( dclone );
>
>   sub try {
>     my @b = @{ dclone( \@_ ) };
>     ...
>   }
>
> Storable is a standard module that is installed with Perl. For a list of all standard pragmatics and modules, see `perldoc perlmodlib`.
>
>
0
jph4dotcom
10/16/2011 6:10:06 PM
On 16/10/2011 19:10, JPH wrote:
>
> On 10/16/2011 04:05 AM, Shawn H Corey wrote:
>> On 11-10-15 07:44 PM, Rob Dixon wrote:
>>>
>>> sub try {
>>> my @b;
>>> foreach my $row (@_) {
>>> push @b, [@$row];
>>> }
>>> :
>>> }
>>>
>>
>> Or you could use dclone() from Storable:
>>
>> use Storable qw( dclone );
>>
>> sub try {
>> my @b = @{ dclone( \@_ ) };
>> ...
>> }
>>
>> Storable is a standard module that is installed with Perl. For a list
>> of all standard pragmatics and modules, see `perldoc perlmodlib`.
>
> Thanks! My script seems to work with dclone.
>
> Though the (deep) recursion takes a lot of time ...
> What is your opinion, would it pay off (in performance) when I rewrite
> the script in such a way that I do not use dclone, but string
> manipulation routines instead? So:
> - passing a single dimension array containing 16 elements with
> 16-character strings and doing substr()
> - instead of passing a 2 dimensional (16x16) array passing 1-character
> strings and doing dclone
> Every pass I only change a single character, then I run some tests and
> so on.

I suggest you try a simplified version of my code, which is bound to be 
faster than calling dclone:

   sub try {
     my @b = map [@$_], @_;
     :
   }

Whether it is fast enough only you can tell.

I would also suggest an intermediate solution, where you have a
sixteen-element array, each of sixteen characters. Rather than using
substr you could look at unpack, or possibly split and join.

It is hard to help you further without knowing more about the problem
you are solving.

Rob
0
rob
10/16/2011 10:18:17 PM
On 16/10/2011 23:18, Rob Dixon wrote:
> On 16/10/2011 19:10, JPH wrote:
>>
>> Every pass I only change a single character, then I run some tests and
>> so on.

I wonder if it is possible to write your subroutine by using a single
global array and remembering the change so that you can undo it before
the code exits?

   my @data = (...);

   sub try {
     my $old = $data[0][1];
     $data[0][1] = '7';
     ...
     $data[0][1] = $old;
     return 3;
   }

Only remembering a single scalar will be many times more efficient than
remembering the entire 256 scalars in the array.

Rob
0
rob
10/16/2011 10:42:26 PM
On 16/10/2011 00:08, JPH wrote:
>
> I am passin a two-dimensional array to a sub and when the sub returns,
> the original array has changed. Eventually I want to pass the array into
> a recursive sub, so I want to find a way to circumvent this behaviour.
> Notice how my global is "@a" and the sub local is "@b"
> - Why is this happening
> - How can I properly pass a two dimensional array to a sub, without the
> array in main changing?
>
> Ideas anyone?

Your problem fascinates me. Please would you help us to understand the
purpose of your program?

Rob
0
rob
10/17/2011 6:31:16 PM
Reply:

Similar Artilces:

global variable vs local variable
hi all, i have a scenario like function is called more than 1000 times.in that function i declared a varible and assigning a value .i felt like declare a global varible use it in that function and assign value.which is best.please tell me in performance point of view. thanks in advance  Hai Good Morning you have call  the function  more than 1000 times Better use Global variables, so you can call the function, anywhere.. it has good performance.suppose it you want assign different values to the variables , whenever the function has been called for that use local ...

local variable & global variable
Hello, please see below: script example> var myAge=20; var myName="Ann"; function MyInfo() { var yourAge = myAge + 13; var yourName = "John"; return yourAge; } : : Question : Where are global variable "myAge" and "myName" stored? And Where are local variable "yourAge" and "yourName" stored? They are stored in context area? ...

variable variables?
Hello! How to make a variable receive an increment in the name? I want to do it for example: I have: Label1->Caption = "1"; Label2->Caption = "2"; Label3->Caption = "3"; Label4->Caption = "4"; And I want to do something like that: for (i=1; i<5; i++) { Label+i->Caption = i; } Any idea? Can I do something like that? Thanks and regards Alexandre Create a vector of pointers to the various objects. In your case below, construct a vector (called Labels) of pointers to TLable long enough to hold pointers to...

variable of variables
Say I have 2 scenarios and I want to use a different variable depending on which scenario applies without coding this logic. So I could have a database table t_variables which has: Scenario: Variable: --------- -------- 1 v_name 2 v_company In my Powerbuilder code I'd have values in v_name & v_company. What I'd like to be able to do is to select which variable to use from the table and assign that to something, e.g. select variable into v_variable from t_variables where scenario = 1 so at this point v_variable would be 'v_name'...

variable not a variable
Error:Must declare the variable '@cartDateTime'. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.Data.SqlClient.SqlException: Must declare the variable '@cartDateTime'. Dim connStr As SqlConnection            Dim cmdInsert As SqlCommand            Dim strInsert As String      &n...

Variable Variables
Hi, Maybe the solution is very simple, but how do I create variable variables in vb.net? I want to use the value of a variable as a part of the name of another variable. A very simple example below: code: Dim a As String a = "1" Label a.Text = "hi" page: <asp:Label id="Label1" runat="server">Label</asp:Label> In need this to change a range of values by using just one loop. I can´t do that without creating a variable variable name. Hi, check out this little demo application I created for you: ...

Global variables / special variables / variable identifier with just one character
Expected error message: "Global symbol "$b" requires explicit package name". However, I get result: "test". I've checked the special variables and it looks like $b is one of these. use warnings; use strict; zzz ($b); print "$b\n"; sub zzz{ $_[0] = "test"; } Does it mean - that in general - we should not use one character variables in Perl? thanks adam ------=_NextPart_000_0011_01C4ADBA.05A29580 Content-Type: text/plain; charset="big5" Content-Transfer-Encoding: quoted-printable "Adam" &l...

shared variable versus global variable
Hi, I plan to implement a little timer service for a certain window class to synchronize some actions between all instances of this class. For some reasons I want to avoid the declaration of a global variable. Now I think about the usage of a shared variable for the service in this window class. In the open event I would check if the shared variable is already instantiated and create the service if necessary. On close of the last window of the class the service should be destroyed from the garbage collector. Do you think that this will work? Thanks for hints Chris Wern...

how to change a treeview control contents when global variable is changed
i have built a main window ,and in this window ,i built a treeview control,for some reason,i want to change the global variable,and thus the treeview contents will change (the contents are some records selected from a database,changed the global variables ,the sql where condition is changed also).I have ever tried to use w_main w_main2 to rebuilt it ,but it can not rebuild the treeview control.So how can I get it? Have you deleted all of the TreeViewItems from the control, then specifically called each and every function/event used to populate it? <janehu> wrote i...

Local and global variables
Can someone explain the difference between use vars qw/$defined_by_vars/ ; our $defined_by_our ; $not_explicily_defined = 1 ; Are these all global to the package they are defined it. ...

How to get a URL variable and set it to a local variable
Very easy question I presume. Does anyone know the answer to get a URL variable and set it to a local variable ? Thanks dim myvar as string = Request.QueryString("someURLvar")Mike Banavige~~~~~~~~~~~~Need a site code sample in a different language? Try converting it with: http://converter.telerik.com/...

Passing a variable to a sub (WAS: passing a variable to a module)
This is really more of a question of how to pass a variable to a sub. First off, check out perldoc perlsub. To avoid problems like this, 'use strict' whenever possible at the top of your scripts. Anyway, here's how to fix this: Passing a variable to a sub: All variables passed to subs are put into the @_ array and then passed. Thus, when you do a printStatement($var), the contents of $var are passed to the first element of the @_ array. In the sub in your module, there is no such thing as the variable $var. If you had used 'use strict', you would have ge...

Create local variable
Hi all, Background: IDM 3.5 and the Lotus Notes driver On the subscriber channel: I want to create a local variable which is based off the DN name of the source object. For example, I was a local variable (call it LV1) to be set to the value of the source DN. IE, LV1 = dn=frank,ou=ohio,o=US One more thing with this local variable, i want to switch out the comma (",") with a slash ("/"). LV1 should equal = dn=frank/ou=ohio/o=US. Next, i want to set the destination variable LTPAUsrNm with the value that I calculated above (dn=frank/ou=ohio/o=US). I a...

Defining autoinstantiate variables as global application variables
Hi, I�ve defined several global application variables that were autoinstantiate Non visual classes. After doing that strange problems happened: When saving window objects PB always crashed. No errors when rebuilding PBL�s or regenerate. After moving these global variables to application manager NVUO (defined as global but not autoinstantiate ) all problems disappeared. I�m well aware about the problem defining global autoinstantiate variables at PB 6. Why this problem did not fixed in the last PB 7 build? General info: PB 7 build 7024 , NT 4 SP 5 Shay Shay, ...

Web resources about - sub local variable changes global variable. - perl.beginners

Variable - Wikipedia, the free encyclopedia
Text is available under the Creative Commons Attribution-ShareAlike License ;additional terms may apply. By using this site, you agree to the ...

Westpac interest rate rise is one of many variable loan rate rises
WESTPAC is not alone in hitting its owner-occupier customers with a surprise interest rate rise, as dozens of other variable rate home loans ...

Airbnb upgrades variable pricing tool for hosts
Online home rental group Airbnb is rolling out an upgraded variable pricing tool that automatically raises or cuts room rates based on supply ...

Commonwealth Bank raises variable home loan rates
Home owners' mortgage costs are set to rise by hundreds of dollars a year, after the Commonwealth Bank became the latest bank to hike interest ...

CBA lifts variable home loan rates to offset costs associated with stricter capital requirements
The Commonwealth Bank to lift its home loan interest rates independently of the Reserve Bank to partially offset costs associated with stricter ...

Washington Square Signs Spielbergs, Choi Joins Variable and More
... films and an episode of the HBO comedy series "Girls," on which he plays the role of Ray Ploshansky. New York-based creative collective Variable ...

YouTube v10.32 Tweaks Some Interface Elements And Includes Hints About Virtual Reality Content And Variable ...
Forget Update Wednesday! Monday is the new big day. Not only were we treated to the latest M preview release and the official Marshmallow name, ...

"You have to ignore many variables to think women are paid less than men. California is happy to try." ...
Writes Sarah Ketterer in The Wall Street Journal in "The ‘Wage Gap’ Myth That Won’t Die" (which you can get to without subscribing if you Google ...

Staley: 'A lot of different variables...been a hard year'
... 41° Navigation Home Giants A's Sharks Warriors Kings 49ers Raiders Quakes Insiders More Tickets Shop Watch Staley: 'A lot of different variables...been ...

Expert Reveals the Latest Variable Capacity Technology
Learn about gForce Ultra CRAC equipment, the latest variable capacity technology to lower energy usage and increase reliability.

Resources last updated: 1/13/2016 6:04:37 AM