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.
I am expecting the key_1 might 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_recurse with key_1. This prints test_recurse(key_1).
In the foreach loop, it will make two successive calls to test_recurse:
The first one with A as argument. This will print test_recurse(A).
In the foreach loop, it will make a call to
test_recurse with C as argument. This will print test_recurse(C).
Since $tmp{C} does not exist, this call does not enter in the foreach loop, and directly proceed to the final print and prints X(C). We then go back to the caller (test_recurse with A as argument).
Now that the foreach loop is done, this function moves on to the last print and prints X(A). We then go back to the caller (test_recurse with key_1 as argument).
The second recursive call is to test_recurse with B as argument. This will print test_recurse(B). Since $tmp{B} does not exist, we do not enter the foreach loop and move on to the final print, which prints X(B). We then return to the caller (test_recurse with key_1 as argument).
The foreach loop is now over and we move on to the final print, which prints X(key_1).
Some tips:
Always add use strict and use warnings at the beginning of your scripts.
#{$tmp{'key_1'}} = ("A", "B"); would be clearer as $tmp{'key_1'} = [ 'A', 'B' ].
The whole initialization of %tmp could actually be done with:
my %tmp = (
key_1 => [ 'A', 'B' ],
A => [ 'C' ]
);
You call &main('key_1'); with key_1 as argument, but main does not expect any argument.
To call a function, you don't need &: do test_recurse(\%tmp, 'key_1'); instead of &test_recurse(\%tmp, 'key_1');.
In a comment, you say:
I am just thinking that as if the variable $cell has been replace by C, A, B why the key_1 is 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.
Related
I have a strange behaved (to Python programmer) subroutine, which simplified as the following:
use strict;
use Data::Dumper;
sub a {
my #x;
sub b { push #x, 1; print "inside: ", Dumper(\#x); }
&b;
print "outside: ", Dumper(\#x);
}
&a;
&a;
I found the result is:
inside: $VAR1=[ 1 ]
outside: $VAR1 = [ 1 ]
inside: $VAR1=[1, 1]
outside: $VAR1= []
What I thought is when calling &a, #x is empty array after "my #x" and has one element after "&b", then dead. Every time I call &a, it is the same. so the output should be all $VAR1 = [ 1 ].
Then I read something like named sub routine are defined once in symbol table, then I do "my $b = sub { ... }; &$b;", it seems make sense to me.
How to explain?
As per the "perlref" man page:
named subroutines are created at compile time so their lexical
variables [i.e., their 'my' variables] get assigned to the parent
lexicals from the first execution of the parent block. If a parent
scope is entered a second time, its lexicals are created again, while
the nested subs still reference the old ones.
In other words, a named subroutine (your b), has its #x bound to the parent subroutine's "first" #x, so when a is called the first time, b adds a 1 to #x, and both the inner and outer copies refer to this same version. However, the second time a is called, a new #x lexical is created, but b still points to the old one, so it adds a second 1 to that list and prints it (inner), but when it comes time for a to print its version, it prints out the (empty) brand new lexical (outer).
Anonymous subroutines don't exhibit this problem, so when you write my $b = sub { ... }, the inner #x always refers to the "current" version of a's lexical #x.
I am not able to understand if I uncommented the return line then output will be "CODE" else "SCALAR".. why it is so?
use strict;
sub test {
my ($abc,$grab) = #_;
print 'i m here';
print $abc;
## return []; if uncommented then output will be "REF" else "SCALAR"
}
my $pass= "i m good";
my %my_hash = ();
$my_hash{'fun'} = \&test($pass);
print ref($my_hash{'fun'})
Without implicit return, a subroutine returns the value of the last expression evaluated. print returns 1 on success, i.e. a scalar.
\&test($pass) is the same as \ test($pass), i.e. it evaluates to the reference to the value returned by the sub test. If it returns 1 from print, you'll get SCALAR, if it returns [], you'll get REF, because you have a reference to a reference to an array. You can verify it by dereferencing it, too:
print ${ $my_hash{fun} }, ': ', ref $my_hash{fun}, "\n";
You are not taking a reference to a function.
When you write:
\&test($pass);
that is a function invocation (you have an argument list).
Therefore, the function test is invoked with the argument $pass and then you take a reference to the returned value (you should not prefix function invocations with & unless you know and specifically desire what it does).
If you want a reference to test, you should use
$my_hash{'fun'} = \&test; ### (1)
If you want a reference to a function that invokes test with the currently in scope argument $pass, you should use:
$my_hash{'fun'} = sub { test($pass) }; ### (2)
Note that the latter will create a closure over the currently in scope variable $pass. To invoke (1), you use $my_hash{fun}->($some_arg). To invoke (2), you use $my_hash{fun}->().
I am a newbie in perl, I have defined a function
sub ex_arg($_)
{
print "$_[0]\n";
print "$_[1]\n";
print "$_[2]\n";
}
1;
in another page i am calling that page.
require "ex_arg.pl";
ex_arg(1,2,3);
ex_arg(1,,3); #in the second function i want the second parameter to be null
1;
is it possible to do this. am not getting the second parameter instead the third parameter is coming as the second parameter.
Am i doing something wrong. please correct me.
Thanks in advance.
The problem is that your argument list does not retain an empty value for the second argument before it is passed to the subroutine. The list 1,,3 will expand into the same list as 1,3.
You'll need to pass some value that actually exists, such as undef or the empty string.
ex_arg(1, undef, 3);
Then perhaps something like
sub ex_arg {
my ($arg1, $arg2, $arg3) = #_;
if (! defined($arg2)) { # checking if arg2 is empty
# do something
}
}
On a related note, you should not use prototypes in your subroutine declaration unless you know what it does. They are used to create specific behaviour in subroutines, and it has nothing to do with how other languages work, with regard to variables in the subroutine.
sub foo ( ... ) {
#^^^^^^^----- prototypes
sub foo { # this is the standard way to declare
Try this,
ex_arg(1, undef, 3);
ex_arg(1, , 3) for perl is same thing as ex_arg(1, 3)
perl -MO=Deparse -e 'ex_arg(1, , 3);'
ex_arg(1, 3); # <<<<<< deparsed
Side notes; if you don't want to use prototypes then sub ex_arg {..} is what you want.
Prefer my ($x,$y) = #_; over $_[0] and $_[1].
Newbie in Perl again here, trying to understand closure in Perl.
So here's an example of code which I don't understand:
sub make_saying {
my $salute = shift;
my $newfunc = sub {
my $target = shift;
print "$salute, $target!\n";
};
return $newfunc; # Return a closure
}
$f = make_saying("Howdy"); # Create a closure
$g = make_saying("Greetings"); # Create another closure
# Time passes...
$f->("world");
$g->("earthlings");
So my questions are:
If a variable is assigned to a function, is it automatically a reference to that function?
In that above code, can I write $f = \make_saying("Howdy") instead? And when can I use the & because I tried using that in passing the parameters (&$f("world")) but it doesn't work.
and lastly, in that code above how did the strings world and earthlings get appended to the strings Howdy and Greetings.
Note: I understand that $f is somewhat bound to the function with the parameter "Howdy" so that's my understanding how "world" got appended. What I don't understand is the 2nd function inside. How that one operates its magic. Sorry I really don't know how to ask this one.
In Perl, scalar variables cannot hold subroutines directly, they can only hold references. This is very much like scalars cannot hold arrays or hashes, only arrayrefs or hashrefs.
The sub { ... } evaluates to a coderef, so you can directly assign it to a scalar variable. If you want to assign a named function (e.g. foo), you have to obtain the reference like \&foo.
You can call coderefs like $code->(#args) or &$code(#args).
The code
$f = \make_saying("Howdy")
evaluates make_saying("Howdy"), and takes a reference to the returned value. So you get a reference that points to a coderef, not a coderef itself.
Therefore, it can't be called like &$f("world"), you need to dereference one extra level: &$$f("world").
A closure is a function that is bound to a certain environment.
The environment consists of all currently visible variables, so a closure always remembers that scope. In the code
my $x;
sub foo {
my $y;
return sub { "$x, $y" };
}
foo is a closure over $x, as the outer environment consists of $x. The inner sub is a closure over $x and $y.
Each time foo is executed, we get a new $y and therefore a new closure. Most importantly $y does not "go out of scope" when foo is left, but it will be "kept alive" as it's still reachable from the closure returned.
In short: $y is a "local state" of the closure returned.
When we execute make_saying("Howdy"), the $salute variable is set to Howdy. The returned closure remembers that scope.
When we execute it again with make_saying("Greetings"), the body of make_saying is evaluated again. The $salute is now set to Greetings, and the inner sub closes over this variable. This variable is separate from the previous $salute, which still exists, but isn't accessible except through the first closure.
The two greeters have closed over separate $salute variables. When they are executed, their respective $salute is still in scope, and they can access and modify the value.
If a variable is asigned to a function, is it automatically a
reference to that function?
No. In example the function make_saying return reference another function. Such closures do not have name and can catch a variable from outside its scope (variable $salute in your example).
In that above code, can i write $f = \make_saying("Howdy") instead?
And when can i use the & cause i tried using that in passing the
parameters (&$f("world")) but it doesnt work.
No. $f = \make_saying("Howdy") is not what you think (read amon post for details). You can write $f = \&make_saying; which means "put into $f reference to function make_saying". You can use it later like this:
my $f = \&make_saying;
my $other_f = $f->("Howdy");
$other_f->("world");
and lastly, In that code above how in he** did the words world and
earthlings got appended to the words howdy and greetings.
make_saying creating my variable which goes into lamda (my $newfunc = sub); that lambda is returned from make_saying. It holds the given word "Howdy" through "closing" (? sorry dont know which word in english).
Every time you call the subroutine 'make_saying', it:
creates a DIFFERENT closure
assigns the received parameter to the scalar '$salute'
defines (creates but not execute) an inner anonymous subroutine:
That is the reason why at that moment nothing is assigned to the scalar
$target nor is the statement print "$salute, $target!\n"; executed .
finally the subroutine 'make_saying' returns a reference to the inner anonymous subroutine, that reference becomes the only way to call the (specific) anonymous subroutine.
Ever time you call each anonymous subroutine, it:
assign the received parameter to the scalar $target
sees also the scalar $salute that will have the value assigned at the moment in which was created the anonymous subroutine (when was called its parent subroutine make_saying
finally executes the statement print "$salute, $target!\n";
I was always sure that if I pass a Perl subroutine a simple scalar, it can never change its value outside the subroutine. That is:
my $x = 100;
foo($x);
# without knowing anything about foo(), I'm sure $x still == 100
So if I want foo() to change x, I must pass it a reference to x.
Then I found out this is not the case:
sub foo {
$_[0] = 'CHANGED!';
}
my $x = 100;
foo($x);
print $x, "\n"; # prints 'CHANGED!'
And the same goes for array elements:
my #arr = (1,2,3);
print $arr[0], "\n"; # prints '1'
foo($arr[0]);
print $arr[0], "\n"; # prints 'CHANGED!'
That kinda surprised me. How does this work? Isn't the subroutine only gets the value of the argument? How does it know its address?
In Perl, the subroutine arguments stored in #_ are always aliases to the values at the call site. This aliasing only persists in #_, if you copy values out, that's what you get, values.
so in this sub:
sub example {
# #_ is an alias to the arguments
my ($x, $y, #rest) = #_; # $x $y and #rest contain copies of the values
my $args = \#_; # $args contains a reference to #_ which maintains aliases
}
Note that this aliasing happens after list expansion, so if you passed an array to example, the array expands in list context, and #_ is set to aliases of each element of the array (but the array itself is not available to example). If you wanted the latter, you would pass a reference to the array.
Aliasing of subroutine arguments is a very useful feature, but must be used with care. To prevent unintended modification of external variables, in Perl 6 you must specify that you want writable aliased arguments with is rw.
One of the lesser known but useful tricks is to use this aliasing feature to create array refs of aliases
my ($x, $y) = (1, 2);
my $alias = sub {\#_}->($x, $y);
$$alias[1]++; # $y is now 3
or aliased slices:
my $slice = sub {\#_}->(#somearray[3 .. 10]);
it also turns out that using sub {\#_}->(LIST) to create an array from a list is actually faster than [ LIST ] since Perl does not need to copy every value. Of course the downside (or upside depending on your perspective) is that the values remain aliased, so you can't change them without changing the originals.
As tchrist mentions in a comment to another answer, when you use any of Perl's aliasing constructs on #_, the $_ that they provide you is also an alias to the original subroutine arguments. Such as:
sub trim {s!^\s+!!, s!\s+$!! for #_} # in place trimming of white space
Lastly all of this behavior is nestable, so when using #_ (or a slice of it) in the argument list of another subroutine, it also gets aliases to the first subroutine's arguments:
sub add_1 {$_[0] += 1}
sub add_2 {
add_1(#_) for 1 .. 2;
}
This is all documented in detail in perldoc perlsub. For example:
Any arguments passed in show up in the array #_. Therefore, if you called a function with two arguments, those would be stored in $_[0] and $_[1]. The
array #_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the
corresponding argument is updated (or an error occurs if it is not updatable). If an argument is an array or hash element which did not exist when the
function was called, that element is created only when (and if) it is modified or a reference to it is taken. (Some earlier versions of Perl created the
element whether or not the element was assigned to.) Assigning to the whole array #_ removes that aliasing, and does not update any arguments.
Perl passes arguments by reference, not by value. See http://www.troubleshooters.com/codecorn/littperl/perlsub.htm