perl subroutine argument lists - "pass by alias"? - perl

I just looked in disbelief at this sequence:
my $line;
$rc = getline($line); # read next line and store in $line
I had understood all along that Perl arguments were passed by value, so whenever I've needed to pass in a large structure, or pass in a variable to be updated, I've passed a ref.
Reading the fine print in perldoc, however, I've learned that #_ is composed of aliases to the variables mentioned in the argument list. After reading the next bit of data, getline() returns it with $_[0] = $data;, which stores $data directly into $line.
I do like this - it's like passing by reference in C++. However, I haven't found a way to assign a more meaningful name to $_[0]. Is there any?

You can, its not very pretty:
use strict;
use warnings;
sub inc {
# manipulate the local symbol table
# to refer to the alias by $name
our $name; local *name = \$_[0];
# $name is an alias to first argument
$name++;
}
my $x = 1;
inc($x);
print $x; # 2

The easiest way is probably just to use a loop, since loops alias their arguments to a name; i.e.
sub my_sub {
for my $arg ( $_[0] ) {
code here sees $arg as an alias for $_[0]
}
}

A version of #Steve's code that allows for multiple distinct arguments:
sub my_sub {
SUB:
for my $thisarg ( $_[0] ) {
for my $thatarg ($_[1]) {
code here sees $thisarg and $thatarg as aliases
last SUB;
}
}
}
Of course this brings multilevel nestings and its own code readability issues, so use it only when absolutely neccessary.

Related

run a subroutine by using argument

My code:
my $aaa = "abc";
sub myp{
print "$_";
}
myp($aaa);
I hope myp can print the argument it get.
But it said
Use of uninitialized value $_ in string at ./arg line 17.
The arguments to a subroutine in Perl are passed in the #_ array. This is not the same as the $_ variable.
A common idiom is to "unpack" these arguments in the first line of a function, e.g.
sub example {
my ($arg1, $arg2) = #_;
print "$arg1 and $arg2";
}
It's also possible to refer to arguments directly as elements of #_, e.g. as $_[0], but this is much harder to read and as such is best avoided.
I usually do something like:
my $first_arg = shift #_;
my $second_arg = shift #_;
You can also use the method of the other response:
my ($first_arg, $second_arg) = #_;
But be careful saying:
my $first_arg = #_;
Since you will get the number of arguments passed to the subroutine.
When you refer to $_ you are referencing the default string variable, you probably want in this case to refer #_, if you want to get a specific argument, you must say $_[narg], be also careful passing arrays to subroutines if you do:
some_sub(#myarray);
You will pass the entire array as it was the argument list, instead you should say:
some_sub(\#myarray);

Perl: passing hash by ref using rule1

I am still unclear about why by ref portion is showing undefined value for %Q and $_ uninitialized. I have been looking through perlreftut and still unable to see what I have done wrong. Passing the hash as a flat array has no issue.
Doing it by ref with testRef(\%mkPara) passes a scalar hash reference to the subroutine, right? So, does my %Q = %{$_} not turn it back into a hash?
use strict;
use diagnostics;
use warnings;
my %mkPara = ('aa'=>2,'bb'=>3,'cc'=>4,'dd'=>5);
sub testFlat
{
my %P = #_;
print "$P{'aa'}, $P{'bb'}, ", $P{'cc'}*$P{'dd'}, "\n";
}
sub testRef
{
my %Q = %{$_}; #can't use an undefined value as HASH reference
#print $_->{'aa'}, "\n";#Use of uninitialized value
print $Q{'aa'},"\n";
}
#testFlat(%mkPara);
testRef(\%mkPara);
When you use arguments in a function call (\%mkPara in your case), you can access them through #_ array inside the function.
Here, you pass a single argument to the function : \%mkPara, which you can then access by accessing the first element of #_ by using $_[0].
$_ is the default variable for some builtin functions/operators (print, m//, s///, chomp and a lot more). Usually seen in while or for loops. But in your code, you have no reason to use it (you are never setting it to anything, so it's still set to undef, hence the error "Can't use an undefined value as a HASH reference".
So your function should actually be :
sub testRef
{
my %Q = %{$_[0]}; # instead of %{$_}
print $_[0]->{'aa'}, "\n"; # instead of $_->{'aa'}
print $Q{'aa'},"\n";
}
If needed, you can find more about functions on perlsub.
However, as #Ikegami pointed out in the comments, using my %Q = %{$_[0]}; creates a copy of the hash you sent to the function, which in most cases (including that one where you just print a key of the hash) is very suboptimal as you could just use a hashref (like you are doing when you do $_[0]->{'aa'}).
You can use hash references like this (roughly the same example as the answer of #Zaid) :
sub testRef
{
my ( $Q ) = #_;
print $Q->{aa} ;
print $_, "\n" for keys %$Q;
}
testRef(\%mkPara);
There are quite a lot of resources about references online, for instance perlreftut that you were already looking at.
This can seem a bit tricky at first, but the reason is that $_ is not the same as #_.
From perlvar:
$_ is the implicit/"default" variable that does not have to be spelled out explicitly for certain functions (e.g. split )
Within a subroutine the array #_ contains the parameters passed to that subroutine
So the reason why
my %Q = %{$_};
says you can't use an undefined value as hash reference is because $_ is not defined.
What you really need here is
my %Q = %{$_[0]};
because that is the first element of #_, which is what was passed to testRef in the first place.
In practice I tend to find myself doing things a little differently because it lends itself to flexibility for future modifications:
sub testRef {
my ( $Q ) = #_;
print $_, "\n" for keys %$Q; # just as an example
}

Perl map passing arguments

I'm trying map() with my own subroutine. When I tried it with a Perl's builtin function, it works. But when I tried map() with my own subroutine, it fails.
I couldn't point out what makes the error.
Here is the code snippet.
#!/usr/bin/perl
use strict;
sub mysqr {
my ($input) = #_;
my $answer = $input * $input;
return $answer;
}
my #questions = (1,2,3,4,5);
my #answers;
#answers = map(mysqr, #questions); # doesn't work.
#answers = map {mysqr($_)} #questions; #works.
print "map = ";
print join(", ", #answers);
print "\n";
Map always assigns an element of the argument list to $_, then evaluates the expression. So map mysqr($_), 1,2,3,4,5 calls mysqr on each of the elements 1,2,3,4,5, because $_ is set to each of 1,2,3,4,5 in turn.
The reason you can often omit the $_ when calling a built-in function is that many Perl built-in functions, if not given an argument, will operate on $_ by default. For example, the lc function does this. Your mysqr function doesn't do this, but if you changed it to do this, the first form would work:
sub mysqr {
my $input;
if (#_) { ($input) = #_ }
else { $input = $_ } # No argument was given, so default to $_
my $answer = $input * $input;
return $answer;
}
map(mysqr, 1,2,3,4,5); # works now
The difference is that in the second case, you are explicitly passing the argument, and in the first one, you pass nothing.
#answers = map(mysqr, #questions); # same as mysqr(), no argument passed
#answers = map {mysqr($_)} #questions; # $_ is passed on to $input
You might be thinking of the fact that many Perl built-in functions use $_ when no argument is given. This is, however, not the default behaviour of user defined subroutines. If you want that functionality, you need to add it yourself. Though be warned that it often is not a good idea.
Note that if you use use warnings, which you always should, you will get a descriptive error:
Use of uninitialized value $input in multiplication (*) at foo.pl line 8.
Which tells you that no data is passed to $input.
Not using warnings is not removing errors from your code, it is merely hiding them, much like hiding the "low oil" warning lamp in a car does not prevent engine failure.

How to run an anonymous function in Perl?

(sub {
print 1;
})();
sub {
print 1;
}();
I tried various ways, all are wrong...
(sub { ... }) will give you the pointer to the function so you must call by reference.
(sub { print "Hello world\n" })->();
The other easy method, as pointed out by Blagovest Buyukliev would be to dereference the function pointer and call that using the { } operators
&{ sub { print "Hello World" }}();
Yay, I didn't expect you folks to come up with that much possibilities. But you're right, this is perl and TIMTOWTDI: +1 for creativitiy!
But to be honest, I use hardly another form than the following:
The Basic Syntax
my $greet = sub {
my ( $name ) = #_;
print "Hello $name\n";
};
# ...
$greet->( 'asker' )
It's pretty straight forward: sub {} returns a reference to a sub routine, which you can store and pass around like any other scalar. You can than call it by dereferencing. There is also a second syntax to dereference: &{ $sub }( 'asker' ), but I personally prefer the arrow syntax, because I find it more readable and it pretty much aligns with dereferencing hashes $hash->{ $key } and arrays $array->[ $index ]. More information on references can be found in perldoc perlref.
I think the other given examples are a bit advanced, but why not have a look at them:
Goto
sub bar {goto $foo};
bar;
Rarely seen and much feared these days. But at least it's a goto &function, which is considered less harmful than it's crooked friends: goto LABEL or goto EXPRESSION ( they are deprecated since 5.12 and raise a warning ). There are actually some circumstances, when you want to use that form, because this is not a usual function call. The calling function ( bar in the given example ) will not appear in the callling stack. And you don't pass your parameters, but the current #_ will be used. Have a look at this:
use Carp qw( cluck );
my $cluck = sub {
my ( $message ) = #_;
cluck $message . "\n";
};
sub invisible {
#_ = ( 'fake' );
goto $cluck;
}
invisible( 'real' );
Output:
fake at bar.pl line 5
main::__ANON__('fake') called at bar.pl line 14
And there is no hint of an invisible function in the stack trace. More info on goto in perldoc -f goto.
Method Calls
''->$foo;
# or
undef->$foo;
If you call a method on an object, the first parameter passed to that method will be the invocant ( usually an instance or the class name ). Did i already say that TIMTOWTCallAFunction?
# this is just a normal named sub
sub ask {
my ( $name, $question ) = #_;
print "$question, $name?\n";
};
my $ask = \&ask; # lets take a reference to that sub
my $question = "What's up";
'asker'->ask( $question ); # 1: doesn't work
my $meth_name = 'ask';
'asker'->$meth_name( $question ); # 2: doesn't work either
'asker'->$ask( $question ); # 1: this works
In the snippet above are two calls, which won't work, because perl will try to find a method called ask in package asker ( actually it would work if that code was in the said package ). But the third one succeeds, because you already give perl the right method and it doesn't need to search for it. As always: more info in the perldoc I can't find any reason right now, to excuse this in production code.
Conclusion
Originally I didn't intend to write that much, but I think it's important to have the common solution at the beginning of an answer and some explanations to the unusual constructs. I admit to be kind of selfish here: Every one of us could end up maintaining someones code, who found this question and just copied the topmost example.
There is not much need in Perl to call an anonymous subroutine where it is defined. In general you can achieve any type of scoping you need with bare blocks. The one use case that comes to mind is to create an aliased array:
my $alias = sub {\#_}->(my ($x, $y, $z));
$x = $z = 0;
$y = 1;
print "#$alias"; # '0 1 0'
Otherwise, you would usually store an anonymous subroutine in a variable or data structure. The following calling styles work with both a variable and a sub {...} declaration:
dereference arrow: sub {...}->(args) or $code->(args)
dereference sigil: &{sub {...}}(args) or &$code(args)
if you have the coderef in a scalar, you can also use it as a method on regular and blessed values.
my $method = sub {...};
$obj->$method # same as $method->($obj)
$obj->$method(...) # $method->($obj, ...)
[1, 2, 3]->$method # $method->([1, 2, 3])
[1, 2, 3]->$method(...) # $method->([1, 2, 3], ...)
I'm endlessly amused by finding ways to call anonymous functions:
$foo = sub {say 1};
sub bar {goto $foo};
bar;
''->$foo; # technically a method, along with the lovely:
undef->$foo;
() = sort $foo 1,1; # if you have only two arguments
and, of course, the obvious:
&$foo();
$foo->();
You need arrow operator:
(sub { print 1;})->();
You might not even need an anonymous function if you want to run a block of code and there is zero or one input. You can use map instead.
Just for the side effect:
map { print 1 } 1;
Transform data, take care to assign to a list:
my ($data) = map { $_ * $_ } 2;
# ------------------------------------------------------
# perl: filter array using given function
# ------------------------------------------------------
sub filter {
my ($arr1, $func) = #_;
my #arr2=();
foreach ( #{$arr1} ) {
push ( #arr2, $_ ) if $func->( $_ );
};
return #arr2;
}
# ------------------------------------------------------
# get files from dir
# ------------------------------------------------------
sub getFiles{
my ($p) = #_;
opendir my $dir, $p or die "Cannot open directory: $!";
my #files=readdir $dir;
closedir $dir;
#return files and directories that not ignored but not links
return filter \#files, (sub { my $f = $p.(shift);return ((-f $f) || (-d $f)) && (! -l $f) } );
}

What is the magic behind perl read() function and buffer which is not a ref?

I do not get to understand how the Perl read($buf) function is able to modify the content of the $buf variable. $buf is not a reference, so the parameter is given by copy (from my c/c++ knowledge). So how come the $buf variable is modified in the caller ?
Is it a tie variable or something ? The C documentation about setbuf is also quite elusive and unclear to me
# Example 1
$buf=''; # It is a scalar, not a ref
$bytes = $fh->read($buf);
print $buf; # $buf was modified, what is the magic ?
# Example 2
sub read_it {
my $buf = shift;
return $fh->read($buf);
}
my $buf;
$bytes = read_it($buf);
print $buf; # As expected, this scope $buf was not modified
No magic is needed -- all perl subroutines are call-by-alias, if you will. Quoth perlsub:
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).
For example:
sub increment {
$_[0] += 1;
}
my $i = 0;
increment($i); # now $i == 1
In your "Example 2", your read_it sub copies the first element of #_ to the lexical $buf, which copy is then modified "in place" by the call to read(). Pass in $_[0] instead of copying, and see what happens:
sub read_this {
$fh->read($_[0]); # will modify caller's variable
}
sub read_that {
$fh->read(shift); # so will this...
}
read() is a built-in function, and so can do magic. You can accomplish something similar with your own functions, though, by declaring a function prototype:
sub myread(\$) { ... }
The argument declaration \$ means that the argument is implicitly passed as a reference.
The only magic in the built-in read is that it works even when called indirectly or as a filehandle method, which doesn't work for regular functions.