Perl: function returns reference or copy? - perl

Im a newbie in perl. So the question might sound something naive.
I have two following functions
#This function will return the reference of the array
sub getFruits1
{
my #fruits = ('apple', 'orange', 'grape');
return \#fruits;
}
But in the following case?
#How it returns?
sub getFruits2
{
my #fruits = ('apple', 'orange', 'grape');
return #fruits;
}
Will getFruits2 return a reference and a new copy of that array will be created?

The getFruits2 subroutine returns a list, which can be assigned to a new array like this
my #newfruits = getFruits2();
And yes, it will produce a copy of the data in the array

getFruits1 will return a reference to an array. The \ creates a reference.
getFruits2 will return a list of the values in #fruits. It won't return a reference. You'll only get a copy of the array if you assign the return value to an array.

getFruits1 returns a reference.No new array is created.
getFruits2 returns a list
An example of Perl referencing
#!/usr/bin/perl -w
use strict;
my #array = ('a','b','c');
printf("[%s]\n",join('',#array));
my $ref=\#array;
${#{$ref}}[0]='x'; # Modifies #array using reference
printf("[%s]\n",join('',#array));

The only thing that can be returned by a sub is a list of scalars. Arrays can't be returned.
\#fruits
evaluates to a reference, so
return \#fruits;
returns a reference. In list context,
#fruits
evaluates to a list of the elements of #fruits, so
return #fruits;
returns a list of the elements of #fruits if the sub is evaluated in list context.

Related

Perl: Return anonymous array from a subroutine

I'm trying to return an anonymous array from a subroutine, however, when dumping the returned variable I only see one value (I'm expecting two).
Here is my code:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $fruits_ref = generate_fruits();
print "Fruits: " . Dumper($fruits_ref) . "\n";
sub generate_fruits
{
return ("Apple", "Orange");
}
This outputs:
Fruits: $VAR1 = 'Orange';
How do I get the subroutine to return that array ref?
Anonymous arrays are constructed with square brackets.
return [ 'Apple', 'Orange' ]
You're not returning an array (or a reference to array), you're returning a list. A reference to anonymous array is ["Apple", "Orange"]
List becomes its last element when you pass it to scalar context. To pass to list context, you could do
my #fruits = generate_fruits();
But that is likely not what you need - you seem to need a reference. For that, just use square brackets.
Oh, another alternative is
my $fruits_ref = [generate_fruits()];

Perl return scalar value or first element if it's array in one line

$scalar = function();
if function return scalar it is ok, but if return array i need to assign first element from array. how to write it in Perl in one line?
edit:
Is it possible without variable like this:
call_another_func(function());
Put it in parens if it returns list of elements,
my ($scalar) = function();
same thing, taking first list element,
my $scalar = (function())[0];
or dereference if it returns array reference,
my ($scalar) = #{ function() };
Subs can't return a arrays. They can only return a list of zero or more scalars. The following will pass the first scalars returned by function to call_another_func as an argument:
call_another_func( ( function() )[0] );

perl, function only printing first element of the array

I have an array that has several elements on it but when I pass the array as a parameter to a function and then call the function it only prints out the first element of the array multiple times. For example
my $element;
my $random_variable = "Testing";
my #the_array = ("hello", "bye", "hey");
foreach $element(#the_array)
{
PrintFunction(#the_array, $random_variable)
}
sub PrintFunction{
my ($the_array, $random_variable) = #_;
// other code here
print $the_array . "\n";
}
The result I get from this is
hello
hello
hello
The result I want is to print all the elements of the array as
hello
bye
hey
Change:
PrintFunction(#the_array, $random_variable)
to:
PrintFunction($element, $random_variable)
Your code passes the entire array to the sub, then you only print the 1st element of the array each time because you use the scalar variable $the_array inside the sub. Since foreach grabs each element of the array, you probably meant to use $element.
Add Print #_; to your sub to see what is passed to it. You will see:
hellobyeheyTesting
hellobyeheyTesting
hellobyeheyTesting
It means you are passing the entire array followed by the $random_variable. Therefore, $the_arrayin the sub will be always the first elements of #the_array which is hello. To fix that, you should pass each element of array iteratively by
foreach $element(#the_array)
{
PrintFunction(#element, $random_variable)
}

Perl: Calling a module method inside [ ]

Using an example, let a perl program start in the following fashion:
use strict;
use warnings;
use Time::HiRes;
What's the difference between
my $request_start_epoch = [Time::HiRes::gettimeofday];
and
my $request_start_epoch = Time::HiRes::gettimeofday;
?
The former calls the function in list context, assembles an anonymous array containing the elements of the returned list, and sets $request_start_epoch to a reference to that array.
The latter calls the function in scalar context and stores its return-value in $request_start_epoch.
These will almost always be different; the only time they would be the same is if the function's behavior in scalar context is to wrap up its list-context results in an anonymous array and return a reference to it. I've never seen any method written like that, but I'm sure someone somewhere has done it at some point!
The brackets [] convert what is returned by gettimeofday to an array reference. In your case, it would be a one element array.
Creating an array reference.
$arr_ref = [ 1,2,3,4,5 ];
Deferencing it.
#{ $arr_ref };
Accessing an element.
$ { $array_ref }[0]

Subroutine that returns hash - breaks it into separate variables

I have a subroutine that returns a hash. Last lines of the subroutine:
print Dumper(\%fileDetails);
return %fileDetails;
in this case the dumper prints:
$VAR1 = {
'somthing' => 0,
'somthingelse' => 7.68016712043654,
'else' => 'burst'
}
But when I try to dump it calling the subroutine with this line:
print Dumper(\fileDetailsSub($files[$i]));
the dumper prints:
$VAR1 = \'somthing';
$VAR2 = \0;
$VAR3 = \'somthingelse';
$VAR4 = \7.68016712043654;
$VAR5 = \'else';
$VAR6 = \'burst';
Once the hash is broken, I can't use it anymore.
Why does it happen? And how can I preserve the proper structure on subroutine return?
Thanks,
Mark.
There's no such thing as returning a hash in Perl.
Subroutines take lists as their arguments and they can return lists as their result. Note that a list is a very different creature from an array.
When you write
return %fileDetails;
This is equivalent to:
return ( 'something', 0, 'somethingelse', 7.68016712043654, 'else', 'burst' );
When you invoke the subroutine and get that list back, one thing you can do is assign it to a new hash:
my %result = fileDetailsSub();
That works because a hash can be initialized with a list of key-value pairs. (Remember that (foo => 42, bar => 43 ) is the same thing as ('foo', 42, 'bar', 43).
Now, when you use the backslash reference operator on a hash, as in \%fileDetails, you get a hash reference which is a scalar the points to a hash.
Similarly, if you write \#array, you get an array reference.
But when you use the reference operator on a list, you don't get a reference to a list (since lists are not variables (they are ephemeral), they can't be referenced.) Instead, the reference operator distributes over list items, so
\( 'foo', 'bar', 'baz' );
makes a new list:
( \'foo', \'bar', \'baz' );
(In this case we get a list full of scalar references.) And this is what you're seeing when you try to Dumper the results of your subroutine: a reference operator distributed over the list of items returned from your sub.
So, one solution is to assign the result list to an actual hash variable before using Dumper. Another is to return a hash reference (what you're Dumpering anyway) from the sub:
return \%fileDetails;
...
my $details_ref = fileDetailsSub();
print Dumper( $details_ref );
# access it like this:
my $elem = $details_ref->{something};
my %copy = %{ $details_ref };
For more fun, see:
perldoc perlreftut - the Perl reference tutorial, and
perldoc perlref - the Perl reference reference.
Why not return a reference to the hash instead?
return \%fileDetails;
As long as it is a lexical variable, it will not complicate things with other uses of the subroutine. I.e.:
sub fileDetails {
my %fileDetails;
... # assign stuff
return \%fileDetails;
}
When the execution leaves the subroutine, the variable goes out of scope, but the data contained in memory remains.
The reason the Dumper output looks like that is that you are feeding it a referenced list. Subroutines cannot return arrays or hashes, they can only return lists of scalars. What you are doing is something like this:
print Dumper \(qw(something 0 somethingelse 7.123 else burst));
Perl functions can not return hashes, only lists. A return %foo statement will flatten out %foo into a list and returns the flattened list. To get the return value to be interpreted as a hash, you can assign it to a named hash
%new_hash = fileDetailsSub(...);
print Dumper(\%new_hash);
or cast it (not sure if that is the best word for it) with a %{{...}} sequence of operations:
print Dumper( \%{ {fileDetailsSub(...)} } );
Another approach, as TLP points out, is to return a hash reference from your function.
You can't return a hash directly, but perl can automatically convert between hashes and lists as needed. So perl is converting that into a list, and you are capturing it as a list. i.e.
Dumper( filedetail() ) # list
my %fd = filedetail(); Dumper( \%fd ); #hash
In list context, Perl does not distinguish between a hash and a list of key/value pairs. That is, if a subroutine returns a hash, what it really returns is an list of (key1, value1, key2, value2...). Fortunately, that works both ways; if you take such a list and assign it to a hash, you get a faithful copy of the original:
my %fileDetailsCopy = subroutineName();
But if it wouldn't break other code, it would probably make more sense to have the sub return a reference to the hash instead, as TLP said.