Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

unexpected: inside sub($1,$2) if do // then arguments will be changed

by bdimych (Monk)
on Sep 11, 2011 at 07:34 UTC ( #925326=perlquestion: print w/ replies, xml ) Need Help??
bdimych has asked for the wisdom of the Perl Monks concerning the following question:

> perl -v This is perl, v5.10.1 (*) built for i686-cygwin-thread-multi-64int (with 13 registered patches, see perl -V for more detail) Copyright 1987-2009, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using "man perl" or "perldoc perl". If you have access to + the Internet, point your browser at http://www.perl.org/, the Perl Home Pa +ge. > cat tmp.pl #!/usr/bin/perl sub mysub { die 'single word expected' if (my $name = shift) !~ /^\w+$/; die 'single word expected' if (my $value = shift) !~ /^\w+$/; } $str = "abc def"; $str =~ /(\w+)\s+(\w+)/; mysub($1, $2); > ./tmp.pl single word expected at ./tmp.pl line 4.
perlvar says "read-only and dynamically scoped"
$<digits> ($1, $2, ...) Contains the subpattern from the corresponding set of capturing pa +rentheses from the last successful pattern match, not counting patter +ns matched in nested blocks that have been exited already. (Mnemonic: + like \digits.) These variables are all read-only and dynamically sco +ped to the current BLOCK.
I'm confused a bit
have decided to post here

Comment on unexpected: inside sub($1,$2) if do // then arguments will be changed
Select or Download Code
Replies are listed 'Best First'.
Re: unexpected: inside sub($1,$2) if do // then arguments will be changed
by repellent (Priest) on Sep 11, 2011 at 08:23 UTC
    In mysub(), aliases to the global variables $1 and $2 are held in @_, but those globals don't stay set as you expected for very "long":
    use warnings; use Data::Dumper; sub mysub { warn Dumper \@_; # globals still set die 'single word expected' if (my $name = shift) !~ /^\w+$/; warn Dumper \@_; # you "lost" the globals (due to matching /^ +\w+$/) die 'single word expected' if (my $value = shift) !~ /^\w+$/; } $str = "abc def"; $str =~ /(\w+)\s+(\w+)/; mysub($1, $2); __END__ $VAR1 = [ 'abc', 'def' ]; $VAR1 = [ undef ]; Use of uninitialized value $value in pattern match (m//) at ./t.pl lin +e 12. single word expected at ./t.pl line 12.

    Save off global variables, or avoid using them:
    my ($name, $value) = ($str =~ /(\w+)\s+(\w+)/); mysub($name, $value);
Re: unexpected: inside sub($1,$2) if do // then arguments will be changed
by JavaFan (Canon) on Sep 11, 2011 at 10:19 UTC
    Note that this issue (already explained by others) isn't limited to $1 and frieds. It can happen to other variables as well, including lexical scoped variables:
    use 5.010; use strict; use warnings; my($foo, $bar) = (1, 2); sub baz { say shift; $bar = 3; say shift; } baz $foo, $bar; __END__ 1 3
Re: unexpected: inside sub($1,$2) if do // then arguments will be changed
by ikegami (Pope) on Sep 12, 2011 at 05:05 UTC

    perlvar says "read-only and dynamically scoped"

    They are. mysub does indeed back them up on entry and restore them on exit.

    $ perl -E' sub f { say $1; "b"=~/(b)/; say $1; } "a"=~/(a)/; say $1; f(); say $1; ' a a b a

    The problem is that $_[0] and $_[1] are aliased to $1 and $2, so changing $1 and $2 changes $_[0] and $_[1].

    $ perl -E' sub f { say $_[0]; "b"=~/(b)/; say $_[0]; } "a"=~/(a)/; f($1); ' a b

    Three solutions:

    • /.../; mysub("$1", "$2"); sub mysub { /.../; shift; shift; }
    • my ($x, $y) =~ /.../; mysub($x, $y); sub mysub { /.../; shift; shift; }
    • /.../; mysub($1, $2); sub mysub { my ($x, $y) = @_; /.../; $x; $y; }
Re: unexpected: inside sub($1,$2) if do // then arguments will be changed
by Anonymous Monk on Sep 11, 2011 at 07:42 UTC
    Global variables are global :) copy them mysub( "$1", "$2" );
Re: unexpected: inside sub($1,$2) if do // then arguments will be changed
by Khen1950fx (Canon) on Sep 11, 2011 at 08:52 UTC
    (Mnemonic: like \digits)

    Try it like this: \(&mysub(<$1> <$2>));

    #!/usr/bin/perl -slw use strict; use re 'debug'; sub mysub { die 'single word expected' if (my $name = shift @_) =~ /^\w+$/; die 'single word expected' if (my $value = shift @_) =~ /^\w+$/; } my $str = 'abc def'; $str =~ /(\w+)\s+(\w+)/; print "\(&mysub(<$1> <$2>))";

        It's a dressed up version of this:

        print "'$1' '$2'";

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://925326]
Approved by davido
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (7)
As of 2015-07-29 08:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (261 votes), past polls