How to pass optional parameters to a Perl subroutine? - perl

I wanted to pass two arguments to my subroutine. The first parameter is required, the second parameter I want to be optional. Actually it works for non-array parameter in this script:
deftest ("string value test",9);
sub deftest{
my ($strvalue, $num) = #_;
if (defined $num){
print "\nCHECK 1 - Defined value $num";
} else {
$num //= 99;
}
print "\nstrvalue: $strvalue num: $num\n";
}
When I invoke this subroutine with ("string value test",9); then on the screen:
CHECK 1 - Defined value 9
strvalue: string value test num: 9
When I don't enter the second argument, then the value is 99. So this works fine.
The problem is, when I use the array in the first argument:
my #arrSwap = (1,2,3);
deftest2 (#arrSwap,5);
sub deftest2{
my (#arrSwap, $num) = #_;
if (defined $num){
print "\n\nCHECK 2 - Defined val $num";
} else {
$num //= 55;
}
print "\narrSwap $arrSwap[1] num: $num\n";
}
After invoking this subroutine with deftest2 (#arrSwap,5); then on the screen I have only: arrSwap 2 num: 55
(but 5 would be expected as it is defined).
Why it doesn't work with the array?

Because perl passes a single list as arguments, and assigning my ( #arrSwap, $num ) = #_ will always mean an empty $num, because #arrSwap will consume the entirety of the input.
If you want to do this, you need to pass a reference
my #arrSwap = ( 1,2,3 );
deftest2 ( \#arrSwap, 5);
sub deftest2 {
my ( $arrSwap_ref, $num ) = #_;
$num //= 55;
print "\narrSwap", $arrSwap -> [1], " num: $num\n";
}
Otherwise perl simply has no way to tell whether the last number is part of the list you sent, or an optional parameter.

The arguments to subroutines are lists in Perl. When you assign the arguments to an array, Perl doesn't know how long that array is supposed to be, so there is no way to do this:
sub frobnicate {
my (#foo, $bar) = #_;
}
In that case, $bar will always be undef, because it just assigns the rest of the list to #foo.
Instead, you need to make the array-part of your arguments a reference, and derefence it correctly.
sub frobnicate {
my ($foo, $bar) = #_;
foreach my $element (#{ $foo }) {
# ...
}
}
And then call it with a reference.
frobnicate(\#foo, 123);
Because a reference is a scalar value, you now know how many elements will be in the argument list, and you can have optional arguments at the end of the list.

The array is expanded in the parameter list and forms the first N parameters, with $num appearing at the end
If you pass the array that way then there is no way to tell from within the subroutine how many parameters came from the array, so it is always best to pass an array by reference
Your code would look like this
my #arrSwap = ( 1, 2, 3 );
deftest2( \#arrSwap, 5 );
deftest2( \#arrSwap );
sub deftest2 {
my ( $arrSwap, $num ) = #_;
if ( defined $num ) {
print "\n\nCHECK 2 - Defined val $num";
}
else {
$num = 55;
}
print "\narrSwap $arrSwap->[1] num: $num\n";
}
output
CHECK 2 - Defined val 5
arrSwap 2 num: 5
arrSwap 2 num: 55

Related

Average value function returning random number on empty array

I'm using perl 5.16.
I have the following function to give me the average value inside any given array:
sub GetAvgValue {
my #Array = #_;
my $Sum = 0;
foreach my $CurVal (#Array) {
$Sum += $CurVal;
}
if ( scalar(#Array) ) {
return $Sum / scalar(#Array);
}
else {
return undef;
}
}
I want it to return undef when there are no elements inside the array, but instead it returns a random-looking integer:
print Dumper GetAvgValue([]);
# 1. iteration: $VAR1 = '42311136';
# 2. iteration: $VAR1 = '38006240';
# 3. iteration: $VAR1 = '39394784';
[] is an array reference. You are not using array references in your code. This sub call is therefore wrong:
GetAvgValue([]);
The argument list #_ is now not empty, it contains one value: an array reference. What you should do is:
GetAvgValue();
Send an empty list. Because you assign the array inside the subroutine like this:
my #Array = #_;
If you were using an array reference like [] is, you would be doing this:
my $aref = shift; # or
my $aref = $_[0]; # or
my ($aref, #rest) = #_; # etc
my #Array = #$aref; # dereference
The "random looking value" at the end is the numeric address of the array reference, subjected to a division by 1. Demonstration:
$ perl -lwe'print []'
ARRAY(0x79a7d0)
$ perl -lwe'print []/1'
15443920

Passing a reference as an argument and not naming it in Perl

so I have something like this:
#result = myfun \#args;
I want to do something like this:
sub myfun{
foreach (##_){ $_ = $_**2; } #foreach element the argument is referring to square the element
return ##_; # return the list that the argument is referring to
}
Is there a way to do this?
You can try:
my #args = 1..5;
my #result = myfun( \#args );
say for #result;
sub myfun{
map {$_**2} #{$_[0]};
}
Output:
1
4
9
16
25
As previously mentioned, one could simply use
sub myfun { map { $_ ** 2 } #{ $_[0] } }
my #args = 1..5;
say for myfun(\#args);
But one has to wonder why you wish to pass a reference. The following is simpler:
sub myfun { map { $_ ** 2 } #_ }
my #args = 1..5;
say for myfun(#args);
If you happen to have a reference on the outside, you can always "flatten" it there instead of in the sub.
sub myfun { map { $_ ** 2 } #_ }
my $args = [ 1..5 ];
say for myfun(#$args);
How to tell perl, to pick an element of #_ and dereference it without
creating more references or variables?
To dereference an element of #_, say $_[0], you enclose it in {} and place that in any type of syntax where you would have a variable name (excluding the sigil). E.g. #{$_[0]} instead of #array or ${$_[0]}[0] instead of $array[0].
See http://perlmonks.org?node=References+quick+reference for more examples.

Getting wrong argument value when using #_ in Perl subroutine

I encountered a strange bug while using #_ to pass a single argument to a Perl subroutine. The value passed to a subroutine changes right after entering the subroutine.
Code example:
my $my_def = 0;
print "my_def = $my_def \n";
#someResult = doSomething($my_def);
sub doSomething {
my $def = #_;
print "def = $def \n";
...
}
This returned:
> my_def = 0
> def = 1 # instead of "0"
One more strange thing is that the code worked right for several months before.
The problem was resolved, when I changed it to:
sub doSomething {
my $def = $_[0];
Could anyone tell what could cause the problem? Are there any limitations in using #_ to pass a single argument?
Thanks!
You're getting the correct behaviour, although it isn't what you expected.
A simple rule of thumb for getting local variables from the arguments in a subroutine is to always use parentheses around the variable list in the my (...) declaration:
sub do_something
{
my ($def) = #_;
...
}
The difference is between list context and scalar context. In scalar context, all arrays return the number of elements in the array: 1 in your case. And when you wrote my $def = #_ you provided scalar context. When you used my $def = $_[0] instead you explicitly accessed element zero of the array, which is a scalar (hence the $ sigil) so it all worked again.
In the general case you might have:
sub do_something_else
{
my ($arg1, $arg2, $arg3, #the_rest) = #_;
...
}
Now you have three scalar local variables, $arg1, $arg2, and $arg3, and one array, #the_rest that collects any extra arguments passed.
The answer is simple when a array assigned to scalar value it returns number of elements in the array
It's all about context. Here is an example:
#data = (0, 1, 2);
$count = #data; # imply in scalar context
### $count: 3
$count = scalar #data; # same as above, but force scalar context
### $count: 3
$first = $data[0]; # both sides are in scalar context
### $first: 0
($first) = #data; # both sides are in list context
### $first: 0
$first = shift #data; # get the first, but #data was modified
### $first: 0
### #data: (1, 2)
($second, $third) = #data;
### $second: 1
### $third: 2

Exploring the uses of anonymous subs

I've always been somewhat confused about the purpose and usage of anonymous subs in perl. I understand the concept, but looking for examples and explanations on the value of this practice.
To be clear:
sub foo { ... } # <--- named sub
sub { ... } # <--- anonymous sub
For example:
$ perl -e 'print sub { 1 }'
CODE(0xa4ab6c)
Tells me that sub returns a scalar value. So, I can do:
$ perl -e '$a = sub { 1 }; print $a'
For the same output as above. This of course holds true for all scalar values, so you can load arrays or hashes with anonymous subs.
The question is, how do I use these subs? Why would I want to use them?
And for a gold star, is there any problem which can only be resolved with an anonymous sub?
Anonymous subroutines can be used for all sorts of things.
Callbacks for event handling systems:
my $obj = Some::Obj->new;
$obj->on_event(sub {...});
Iterators:
sub stream {my $args = \#_; sub {shift #$args}}
my $s = stream 1, 2, 3;
say $s->(); # 1
say $s->(); # 2
Higher Order Functions:
sub apply (&#) {
my $code = shift;
$code->() for my #ret = #_;
#ret
}
my #clean = apply {s/\W+/_/g} 'some string', 'another string.';
say $clean[0]; # 'some_string'
Creating aliased arrays:
my $alias = sub {\#_}->(my $x, my $y);
$alias[0]++;
$alias[1] = 5;
say "$x $y"; # '1 5''
Dynamic programming with closures (such as creating a bunch of subroutines that only differ by a small amount):
for my $name (qw(list of names)) {
no strict 'refs';
*$name = sub {... something_with($name) ...};
}
There is no situation where an anonymous subroutine can do anything that a named subroutine can not. The my $ref = sub {...} constructor is equivalent to the following:
sub throw_away_name {...}
my $ref = \&throw_away_name;
without having to bother with deciding on a unique 'throw_away_name' for each sub.
The equivalence also goes the other way, with sub name {...} being equivalent to:
BEGIN {*name = sub {...}}
So other than the name, the code reference created by either method is the same.
To call a subroutine reference, you can use any of the following:
$code->(); # calls with no args
$code->(1, 2, 3); # calls with args (1, 2, 3)
&$code(); # calls with no args
&$code; # calls with whatever #_ currently is
You can even use code references as methods on blessed or unblessed scalars:
my $list = sub {#{ $_[0] }};
say for [1 .. 10]->$list # which prints 1 .. 10
You can use it to create iterators.
use strict;
use warnings;
use 5.012;
sub fib_it {
my ($m, $n) = (0, 0);
return sub {
my $val = ( $m + $n );
$val = 1 unless $val;
($m, $n) = ($n, $val);
return $val;
}
}
my $fibber = fib_it;
say $fibber->() for (1..3); ### 1 1 2
my $fibber2 = fib_it;
say $fibber2->() for (1..5); ### 1 1 2 3 5
say $fibber->() for (1..3); #### 3 5 8
Anonymous subroutines can be used to create closures.
Closure is a notion out of the Lisp world that says if you define an anonymous function in a particular lexical context, it pretends to run in that context even when it's called outside the context.
perlref
What's a closure?
Here's something similar you might have seen before:
#new_list = map { $_ + 1 } #old_list;
And also:
#sorted = sort { $a <=> $b } #unsorted;
Neither of those are anonymous subs, but their behavior can be imitated in your functions with anonymous subs. They don't need the sub keyword because the functions are (essentially) prototyped to have their first argument be a subroutine, and Perl recognizes that as a special case where sub can be left off. (The functions also set the requisite variables to meaningful values before calling the subroutines you provided in order to simplify argument passing, but that's not related.)
You can write your own map-like function:
sub mapgrep (&#) { # make changes and also filter based on defined-ness
my ($func, #list) = #_;
my #new;
for my $i (#list) {
my $j = $func->($i);
push #new, $j if defined $j;
}
}
The magic to make it work with $_ is a bit much to write here - the above version only works for subs that take arguments.
Well I wrote a SAX parser for perl that is event driven. You can pass anonymous subs to the begin/end events on an element.
my $str = "<xml><row><data></data></row></xml>":
my $parser = SAXParser->new();
$parser->when('row')->begin(sub {
my ($element) = #_;
push(#rows, $row);
});
$parser->when('row')->end(sub {
## do something like serialize it or whatever
});
$parser->parse($str);
They are generally used when you want to pass a sub to another bit of code. Often this is a case of "When X happens (in third party code) do Y".
For example. When defining an attribute in Moose, you can specify the default value of that attribute using a sub. Given a class which has, as part of its definition:
has 'size' => (
is => 'ro',
default =>
sub { ( 'small', 'medium', 'large' )[ int( rand 3 ) ] },
predicate => 'has_size',
);
Whenever an instance of that class is created without an explicit size being passed, the sub will be called and the return value will be the size for that object.
If we switch to another language to give a different example, you'll find a similar concept in JavaScript.
var b = document.getElementById('my_button').
b.addEventListener('click', function (e) { alert('clicked!'); });
In your example, you haven't actually called created subroutine. Call is performed with either &$a or $a->() syntax. What you've done is that you stored a reference to subroutine in $a, then stringifyed it and printed result. Compare:
my $a = sub {1};
my $b = sub {1};
print join("\n", $a, $a->(), $b, $b->());
These are subs for the lazy programmer. You can use them for local throw-away functions and can save some typing. Instead of
sub x { ... }
my $function_ptr = \&x;
you can now use
my $function_ptr = sub { ... };
The anonymous functions are also private, and can only be accessed through the $function_ptr, so they don't have an entry in the symbol table.

How do I pass a hash to a function in Perl?

I have a function that takes a variable and an associative array, but I can't seem to get them to pass right. I think this has something to do with function declarations, however I can't figure out how they work in Perl. Is there a good reference for this and how do I accomplish what I need?
I should add that it needs to be passed by reference.
sub PrintAA
{
my $test = shift;
my %aa = shift;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
Pass the reference instead of the hash itself. As in
PrintAA("abc", \%fooHash);
sub PrintAA
{
my $test = shift;
my $aaRef = shift;
print $test, "\n";
foreach (keys %{$aaRef})
{
print $_, " : ", $aaRef->{$_}, "\n";
}
}
See also perlfaq7: How can I pass/return a {Function, FileHandle, Array, Hash, Method, Regex}?
This code works:
#!/bin/perl -w
use strict;
sub PrintAA
{
my($test, %aa) = #_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
}
}
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );
PrintAA("test", %hash);
The key point is the use of the array context in the my() 'statement' in the function.
What does the array context business actually do?
Succinctly, it makes it work correctly.
It means that the first value in the #_ array of arguments is assigned to $test, and the remaining items are assigned to the hash %aa. Given the way I called it, there is an odd number of items in the #_, so once the first item is assigned to $test, there is an even number of items available to assign to %aa, with the first item of each pair being the key ('aaa', 'bbb', 'ccc' in my example), and the second being the corresponding value.
It would be possible to replace %aa with #aa, in which case, the array would have 6 items in it. It would also be possible to replace %aa with $aa, and in that case, the variable $aa would contain the value 'aaa', and the remaining values in #_ would be ignored by the assignment.
If you omit the parentheses around the variable list, Perl refuses to compile the code.
One of the alternative answers showed the notation:
my $test = shift;
my(%aa) = #_;
This is pretty much equivalent to what I wrote; the difference is that after the two my statements, #_ only contains 6 elements in this variation, whereas in the single my version, it still contains 7 elements.
There are definitely other questions in SO about array context.
Actually, I wasn't asking about the my($test, %aa) = #_; I was asking about my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); versus my %hash = { 'aaa' => 1, ... };
The difference is that the { ... } notation generates a hash ref and the ( ... ) notation generates a list, which maps to a hash (as opposed to hash ref). Similarly, [ ... ] generates an array ref and not an array.
Indeed, change the 'main' code so it reads: my(%hash) = { ... }; and you get a run-time (but not compile time) error - treat line numbers with caution since I've added alternative codings to my file:
Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.
Alternatively:
sub PrintAA
{
my $test = shift;
my %aa = #_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
The thing you're fundamentally missing is that an associative array isn't a single argument (though an associative array reference is, as in Paul Tomblin's answer).
It looks like you should pass in a reference to a hash.
sub PrintAA
{
my $test = shift;
my $aa = shift;
if (ref($aa) != "HASH") { die "bad arg!" }
....
}
PrintAA($foo, \%bar);
The reason you can't do a
my %aa = shift;
is because Perl flattens all the arguments to a subroutine into one list, #_. Every element is copied, so passing in by reference avoids those copies as well.
As usual there are several ways. Here is what Perl Best Practices, that most revered of style pointers, has to say about passing parameters to functions:
Use a hash of named arguments for any subroutine that has more than three parameters
But since you have only two, you could get away ;) with passing them directly like this:
my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);
func($scalar, %hash)
And function is defined like this:
sub func {
my $scalar_var = shift;
my %hash_var = #_;
... Do something ...
}
It could be more useful if you could show some code.
All the methods in previous answers work, but this was always the way I preferred to do things like this:
sub PrintAA ($\%)
{
my $test = shift;
my %aa = ${shift()};
print "$test\n";
foreach (keys %aa)
{
print "$_ : $aa{$_}\n";
$aa{$_} = "$aa{$_}+";
}
}
Note: I also changed your code a bit. Perl's double-quoted strings will interpret "$test" to be the value of $test rather than the actual string '$test', so you don't need that many .s.
Also, I was wrong about how the prototypes work. To pass a hash, use this:
PrintAA("test", %hash);
To print a hash reference, use this:
PrintAA("test", %$ref_to_hash);
Of course, now you can't modify the hash referenced by $ref_to_hash because you're sending a copy, but you can modify a raw %hash because you're passing it as a reference.
Arguments to functions get flattened into a single array (#_). So it's usually easiest to pass hashes to a function by reference.
To create a hash:
my %myhash = ( key1 => "val1", key2 => "val2" );
To create a reference to that hash:
my $href = \%myhash
To access that hash by reference;
%$href
So in your sub:
my $myhref = shift;
keys %$myhref;
All the other replies here so far seem rather complicated to me. When I write Perl function I usually "expand" all the passed arguments in the first line of the function.
sub someFunction {
my ( $arg1, $arg2, $arg3 ) = #_;
This is similar to other languages, where you declare functions as
... someFunction ( arg1, arg2, arg3 )
And if you do it that way and pass the hash as the last argument, you'll be fine without any tricks or special magic. E.g.:
sub testFunc {
my ( $string, %hash ) = #_;
print "$string $hash{'abc'} $hash{'efg'} $string\n";
}
my %testHash = (
'abc' => "Hello,",
'efg' => "World!"
);
testFunc('!!!', %testHash);
The output is as expected:
!!! Hello, World! !!!
This works because in Perl arguments are always passed as an array of scalar values and if you pass a hash, its key value/pairs are added to that array. In the sample above, the arguments passed to the function as array (#_) are in fact:
'!!!', 'abc', 'Hello,', 'efg', 'World!'
and '!!!' is simply assigned to %string, while %hash "swallows" all the other arguments, always interpreting one as a key and the next one as value (until all elements are used up).
You cannot pass multiple hashes that way and the hash cannot be the first argument, as otherwise it would swallow everything and leave all other arguments unassigned.
Of course, exactly the same works for array as a last argument. The only difference here is that arrays don't distinguish between keys and values. For them, all arguments left over are values and just get pushed to the array.
Use the following sub to get the hash or hashref - whatever is passed :)
sub get_args { ref( $_[0] ) ? shift() : ( #_ % 2 ) ? {} : {#_}; }
sub PrintAA
{
my $test = shift;
my $aa = get_args(#_);;
# Then
$aa->{somearg} # Do something
$aa->{anotherearg} # Do something
}
Call your function like this:
printAA($firstarg,somearg=>1, anotherarg=>2)
Or like this (no matter):
printAA($firstarg, {somearg=>1, anotherarg=>2})
Or even like this (no matter):
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );
PrintAA("test", %hash);