I have following script that need to understand
&main('key_1');
sub main {
@{$tmp{'key_1'}} = ("A", "B");
@{$tmp{'A'}} = ("C");
&test_recurse(\%tmp, 'key_1');
}
sub test_recurse {
my ($hash, $cell) = @_;
foreach my $cur_subcell (@{$hash->{$cell}}){
&test_recurse($hash, $cur_subcell);
}
print "X($cell)\n";
}
The output:
X(C)
X(A)
X(B)
X(key_1)
I want to understand why the key_1 is printing at the last? I am expecting the key_1 might not be printed at all.
CodePudding user response:
I am expecting the
key_1might not be printed at all
The function test_recurse ends with print "X($cell)\n". This means that it ends by printing its second argument. Since you initially call it with key_1 as argument, it prints X(key_1).
To understand a bit better how the function test_recurse works, I suggest to add some prints as follows:
sub test_recurse {
my ($hash, $cell, $offset) = @_;
print "${offset}test_recurse($cell)\n";
foreach my $cur_subcell (@{$hash->{$cell}}){
&test_recurse($hash, $cur_subcell, $offset . " ");
}
print "${offset}X($cell)\n";
}
Thanks to the addition of $offset, each time you make a recursive call, the prints within this recursive call are indented further to the right. Calling this modified function with test_recurse(\%tmp, 'key_1', ""), you'll get this output:
test_recurse(key_1)
test_recurse(A)
test_recurse(C)
X(C)
X(A)
test_recurse(B)
X(B)
X(key_1)
So, what happens is:
You call
test_recursewithkey_1. This printstest_recurse(key_1). In the foreach loop, it will make two successive calls totest_recurse:The first one with
Aas argument. This will printtest_recurse(A). In the foreach loop, it will make a call totest_recursewithCas argument. This will printtest_recurse(C). Since$tmp{C}does not exist, this call does not enter in theforeachloop, and directly proceed to the final print and printsX(C). We then go back to the caller (test_recursewithAas argument).
Now that the
foreachloop is done, this function moves on to the lastprintand printsX(A). We then go back to the caller (test_recursewithkey_1as argument).The second recursive call is to
test_recursewithBas argument. This will printtest_recurse(B). Since$tmp{B}does not exist, we do not enter theforeachloop and move on to the final print, which printsX(B). We then return to the caller (test_recursewithkey_1as argument).
The
foreachloop is now over and we move on to the finalprint, which printsX(key_1).
Some tips:
Always add
use strictanduse warningsat the beginning of your scripts.@{$tmp{'key_1'}} = ("A", "B");would be clearer as$tmp{'key_1'} = [ 'A', 'B' ].The whole initialization of
%tmpcould actually be done with:my %tmp = ( key_1 => [ 'A', 'B' ], A => [ 'C' ] );You call
&main('key_1');withkey_1as argument, butmaindoes not expect any argument.To call a function, you don't need
&: dotest_recurse(\%tmp, 'key_1');instead of&test_recurse(\%tmp, 'key_1');.
CodePudding user response:
In a comment, you say:
I am just thinking that as if the variable
$cellhas been replace by C, A, B why thekey_1is coming back at the end.
And I think that's probably a good indication of where the confusion lies.
Your test_recurse() subroutine starts with this line:
my ($hash, $cell) = @_;
That defines two new variables called $hash and $cell and then populates them from @_. Because these variables are declared using my, they are lexical variables. That means they are only visible within the block of code where they are declared.
Later on in test_recurse() you call the same subroutine again. And, once again, that subroutine starts with the same declaration statement and creates another two variables called $hash and $cell. These two new variables are completely separate from the original two variables. The original variables still exist and still contain their original values - but you can't currently access them because they are declared in a different call to the subroutine.
So when your various calls to the subroutine end, you rewind back to the original call - and that still has the original two variables which still hold their original values.
