professa has asked for the wisdom of the Perl Monks concerning the following question:

Hi all@perlmonks!

Is it possible to "share" a variable in subroutines? I have a subroutine, in which I declare an array.
This array should be only "visible" inside this subroutine *and* all other subroutines which are called from inside that specific subroutine:

sub callme ($) { my $i = $_[0]; $array[$i] = "printme-"; } sub specific { my @array = [0, 1, 2, 3, 4, 5]; for (my $i=0; $i<6; $i++) { &callme($i); } print @array; }

The print-statement should print:
printme-printme-printme-printme-printme-printme-.
Is this possible? Putting sub callme() inside of sub specific() gives a warning stating to use an anonymous subroutine, but how do I call it from within sub specific() if it's anonymous?
I want to avoid copying around eventually quite large segments of memory when referencing and derefencing that array when passing as \@array to the called subroutine.
btw: the called subroutine does more to the array-element than just setting a new value, so it's recommended to use a subroutine here and not to put the code inside sub specific(). ;-)

Thanx in advance!
Micha

Replies are listed 'Best First'.
Re: Sharing a variable between subroutines
by clintp (Curate) on Dec 28, 2001 at 21:17 UTC
    The most common way is:
    { my @array; sub foo { } sub bar { } }
    Now @array is visible only within foo and bar. If you want to refer to it outside of those, you'll need to pass a copy or a reference to @array to the outside world.

    (update) Of course, daveorg's got the answer to the obvious XY problem.

(jeffa) Re: Sharing a variable between subroutines
by jeffa (Bishop) on Dec 28, 2001 at 21:29 UTC
    If i need for a variable to be 'shared' by other subroutines, then i just pass that variable along as an argument to those subroutines. If you are simply passing a reference to an array, then you are not passing the entire array.

    I rewrote your code with some adjustments:

    use strict; &specific(); sub callme { my ($array,$i) = @_; $array->[$i] = "printme-"; # note the arrow operator } sub specific { my $array = [(0..5)]; &callme($array,$_) for (0..$#$array); print join("\n", @$array), "\n"; }
    The first thing to notice is that $array is a reference:
    # this is not really correct: my @array = [0,1,2,3,4,5]; # use this: my $array = [(0,1,2,3,4,5)]; # or this: my @array = (0,1,2,3,4,5);
    Also, using subroutine prototypes is not recommended. Last note, why iterate through an array one element at a time and pass the index and the array off to another subroutine? Wouldn't simply passing the array reference to a sub that iterates it be better?

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    F--F--F--F--F--F--F--F--
    (the triplet paradiddle)
    
      Aah, I totally forgot about that pointer-stuff (the arrow-operator)...
      I think I'll give this a try. The iteration in the outer sub was just an example.
      I have a two-dimensional array, the y-coordinate ("lines") is determined in the "outer" subroutine and the x-coordinate ("columns") is worked on in the called "inner" subroutine.
      This makes the code more readable IMO.

      Thanks to everyone who bothered to help me and have a happy new y2k2 all!
      Micha

(Ovid) Re: Sharing a variable between subroutines
by Ovid (Cardinal) on Dec 28, 2001 at 21:35 UTC

    Another possibility is to use local with global variables. This use is generally not recommended as global variables are generally a Bad Thing. However, you might at times find this useful. See tilly's Why I Like Functional Programming.

    use strict; use warnings; use vars '$foo'; somesub(); print "\$foo is $foo\n"; sub somesub { local $foo = "Ovid"; anothersub(); } sub anothersub { print "\$foo is $foo\n"; }

    This is mentioned primarily for the sake of completeness. Sometimes rules need to be broken.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      Indeed.

      As I like to say, every good thing has costs. You need to learn to balance the benefits with the costs and decide what works best in your particular situation.

      The reverse is not quite true, not every bad thing has good points. But it is true often enough that I am uncomfortable saying categorically, Thou shalt not...

Re: Sharing a variable between subroutines
by davorg (Chancellor) on Dec 28, 2001 at 21:18 UTC

    The best way would probably be to pass the array into the subroutines as a parameter.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Sharing a variable between subroutines
by rbc (Curate) on Dec 28, 2001 at 23:00 UTC
    You need to pass by reference.
    See section 10.5 Passing Arrays and Hashes by Reference
    of the Camel book.

    Try is code ...
    sub callme () { my ($i, $a ) = @_; ; $a->[$i] = "printme-"; } sub specific { local @array = (0, 1, 2, 3, 4, 5); print "Init @array\n"; for (my $i=0; $i<6; $i++) { &callme($i,\@array); } print "Now @array\n"; } &specific;


    --
    Its like a dog that can sing and dance.
    It's remarkable because it can do it.
    Not that it can do it well.