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

Does anyone know why this code:

use strict; use Data::Dumper; sub sub_b () { my %hash1b = (); $hash1b{"key1"} = "1"; print "calling sub_c from sub_b\n"; sub_c (%hash1b); } sub sub_c (\%) { my ($hash1c) = @_; print "sub_c arguments:" . Dumper (@_); } my %hash1a = (); $hash1a{"key1"} = "1"; print "calling sub_b\n"; sub_b (); print "\n"; print "calling sub_c directly\n"; sub_c (%hash1a);

returns:

calling sub_b calling sub_c from sub_b sub_c arguments:$VAR1 = 'key1'; $VAR2 = 1; calling sub_c directly sub_c arguments:$VAR1 = { 'key1' => 1 };

?
There appears to be a difference in the way sub_c interprets the parameter, depending of it is called directly or from within another sub. Could someone perhaps explain what is going on ?

Replies are listed 'Best First'.
Re: Passing by reference from within a sub
by RichardK (Parson) on Jul 15, 2015 at 12:16 UTC

    Isn't this just an ordering issue ?

    The compiler hasn't seen the definition for sub_c when it compiles sub_b, but it has by the time it gets to the stand alone call of sub_c, hence the differing behaviour. So if you swap the order of your functions it will do what you want.

    use strict; use Data::Dumper; sub sub_c (\%) { my ($hash1c) = @_; print "sub_c arguments:" . Dumper (@_); } sub sub_b () { my %hash1b = (); $hash1b{"key1"} = "1"; print "calling sub_c from sub_b\n"; sub_c (%hash1b); } my %hash1a = (); $hash1a{"key1"} = "1"; print "calling sub_b\n"; sub_b (); print "\n"; print "calling sub_c directly\n"; sub_c (%hash1a);
      Thank you Richard for saving my sanity. It works like expected now.
Re: Passing by reference from within a sub
by Anonymous Monk on Jul 15, 2015 at 12:13 UTC

    I'm pretty sure that's because your first call of sub_c happens before it is defined, hence before its prototype is known.

    The best solution is not not use prototypes, but instead pass a hash reference to sub_c, e.g. sub_c(\%hash1b);

    A quick fix would be to place a "sub sub_c (\%);" before sub_b. Or, you can move sub_c before sub_b, but that won't help if the call tree is more complex than in your example.

      Thanks :) yes this helps.
Re: Passing by reference from within a sub
by AnomalousMonk (Archbishop) on Jul 15, 2015 at 14:24 UTC
Re: Passing by reference from within a sub
by 1nickt (Canon) on Jul 15, 2015 at 12:27 UTC

    I believe you want to change sub_c so that it just looks like:

    sub sub_c { my %hash1c = @_; print "sub_c arguments: " . Dumper \%hash1c; }

    Here's the whole script cleaned up a little:
    [05:25][nick:~/monks]$ cat 1134864.pl #! perl use strict; use warnings; use feature qw/ say /; use Data::Dumper; sub sub_b { my %hash1b; $hash1b{'key1'} = 1; say 'calling sub_c from sub_b'; sub_c( %hash1b ); } sub sub_c { my %hash1c = @_; say 'sub_c arguments: ' . Dumper \%hash1c; } say 'calling sub_b'; sub_b(); my %hash1a; $hash1a{'key1'} = 1; say 'calling sub_c directly'; sub_c( %hash1a ); __END__
    [05:25][nick:~/monks]$ perl 1134864.pl calling sub_b calling sub_c from sub_b sub_c arguments: $VAR1 = { 'key1' => 1 }; calling sub_c directly sub_c arguments: $VAR1 = { 'key1' => 1 };
    The way forward always starts with a minimal test.
      Thank you Nick. Got it working now.
Re: Passing by reference from within a sub
by arvid (Initiate) on Jul 15, 2015 at 12:37 UTC
    Thank you all for handing me these solutions so quickly