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

Fellow monks,

I've got the following bit of code that is losing the contents of a global array upon it's exit.

$canvas->Tk::bind('<Button-1>' => [sub { my ($e,$x,$y) = (@_); shift; push (@coords, $x); push (@coords, $y); }, Ev('x'), Ev('y')]);

Now it's my ascertion, that since @coords was previously defined as a global, I should be able to keep the information in it without having to return it, correct? The values in @coords should not be clobbered as they're not declared as locals in this subroutine.

Is this one of those I'm gonna kick myself when I get an answer things that I'm just obtusely overlooking?


Replies are listed 'Best First'.
Re: Question of scope
by rinceWind (Monsignor) on May 06, 2002 at 20:26 UTC
    I cannot answer your question regarding @coords without knowing precisely how @coords was previously defined as a global.

    Within the use strict; confines, there are two methods which, on the surface appear equivalent, are in fact different.

    use vars qw(@coords); our @coords;
    I may be able to give a more definite answer if you post more of the code. See also 'our' is not 'my' and Our, use vars, and magic, oh my!

    Also, another minor point - the shift; serves no purpose as you have already obtained the arguments from @_.

      My @coords was defined as: my @coords=(); towards the top of my program.

      All I'm attempting to do is push the coordinates on to a global array, but they're being lost after that routine.

      I've done print statements to verfy they did get pushed in to the array, and that $x and $y actually exist ( that I'm not pushing undefined ) so I'm stymied to say the least.

      Hopefully that will clarify my situation so that you may be able to shed a little light on this for me.


      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Question of scope
by gav^ (Curate) on May 07, 2002 at 00:53 UTC
    You might find one of these forms simpler (and shorter): sub { push @coords, @_[1,2] } or
    sub { my (undef, $x, $y) = @_; push @coords, $x, $y; }


Re: Question of scope
by stephen (Priest) on May 07, 2002 at 03:43 UTC

    Be careful, for here you are using a closure. Remember, when an anonymous subroutine is defined, it uses whatever lexical variables are in scope at the time it was created. So:

    use strict; my @foo = (); my $pushit = sub { push @foo, @_; }; $pushit->('apple'); $pushit->('orange'); print @foo, "\n";
    will print "appleorange", but
    use strict; my @foo = (); my $pushit = sub { push @foo, @_; }; my @foo = (); $pushit->('apple'); $pushit->('orange'); print @foo, "\n";
    will print nothing, since the @foo that is printed is not the same @foo that is being populated. (That'll also happen if you're not using strict, and somehow only declare @foo after the closure is created.) If this is the case, it'll show up if you turn warnings on... if the new @foo (or @coords in your case) is in the same scope as the other one. If @coords is file-scoped, you might well want to use 'our' instead of 'my'... that way you're guaranteed a single variable.


Re: Question of scope
by perrin (Chancellor) on May 06, 2002 at 19:33 UTC
    Do you have strict and warnings on? You might just have a typo in the name of the array.