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]
Related
An array in perl is dereferenced like so,
my #array = #{$array_reference};
When trying to assign an array to a dereference without the '#', like,
my #array = {$array_reference};
Perl throws the error, 'Odd number of elements in anonymous hash at ./sand.pl line 22.' We can't assign it to an array variable becauase Perl is confused about the type.
So how can we perform...
my $lastindex = $#{$array_reference};
if Perl struggles to understand that '{$array_reference}' is an array type? It would make more sense to me if this looked like,
my $lastindex = $##{$array_reference};
(despite looking much uglier).
tl;dr: It's $#{$array_reference} to match the syntax of $#array.
{} is overloaded with many meanings and that's just how Perl is.
Sometimes {} creates an anonymous hash. That's what {$array_reference} is doing, trying to make a hash where the key is the stringification of $array_reference, something like "ARRAY(0x7fb21e803280)" and there is no value. Because you're trying to create a hash with a key and no value you get an "odd number of elements" warning.
Sometimes {...} is a block like sub { ... } or if(...) { ... }, or do {...} and so on.
Sometimes it's a bare block like { local $/; ... }.
Sometimes it's indicating the key of a hash like $hash{key} or $hash->{key}.
Preceeded with certain sigils {} makes dereferencing explicit. While you can write $#$array_reference or #$array_reference sometimes you want to dereference something that isn't a simple scalar. For example, if you had a function that returned an array reference you could get its size in one line with $#{ get_array_reference() }. It's $#{$array_reference} to match the syntax of $#array.
$#{...} dereferences an array and gets the index. #{...} dereferences an array. %{...} dereferences a hash. ${...} dereferences a scalar. *{...} dereferences a glob.
You might find the section on Variable Names and Sigils in Modern Perl helpful to see the pattern better.
It would make more sense to me if this looked like...
There's a lot of things like that. Perl has been around since 1987. A lot of these design decisions were made decades ago. The code for deciding what {} means is particularly complex. That there is a distinction between an array and an array reference at all is a bit odd.
$array[$index]
#array[#indexes]
#array
$#array
is equivalent to
${ \#array }[$index]
#{ \#array }[#indexes]
#{ \#array }
$#{ \#array }
See the pattern? Wherever the NAME of an array isused, you can use a BLOCK that returns a reference to an array instead. That means you can use
${ $ref }[$index]
#{ $ref }[#indexes]
#{ $ref }
$#{ $ref }
This is illustrated in Perl Dereferencing Syntax.
Note that you can omit the curlies if the BLOCK contains nothing but a simple scalar.
$$ref[$index]
#$ref[#indexes]
#$ref
$#$ref
There's also an "arrow" syntax which is considered clearer.
$ref->[$index]
$ref->#[#indexes]
$ref->#*
$ref->$#*
Perl is confused about the type
Perl struggles to understand that '{$array_reference}' is an array type
Well, it's not an array type. Perl doesn't "struggle"; you just have wrong expectations.
The general rule (as explained in perldoc perlreftut) is: You can always use a reference in curly braces in place of a variable name.
Thus:
#array # a whole array
#{ $array_ref } # same thing with a reference
$array[$i] # an array element
${ $array_ref }[$i] # same thing with a reference
$#array # last index of an array
$#{ $array_ref } # same thing with a reference
On the other hand, what's going on with
my #array = {$array_reference};
is that you're using the syntax for a hash reference constructor, { LIST }. The warning occurs because the list in question is supposed to have an even number of elements (for keys and values):
my $hash_ref = {
key1 => 'value1',
key2 => 'value2',
};
What you wrote is treated as
my #array = ({
$array_reference => undef,
});
i.e. an array containing a single element, which is a reference to a hash containing a single key, which is a stringified reference (and whose value is undef).
The syntactic difference between a dereference and a hashref constructor is that a dereference starts with a sigil (such as $, #, or %) whereas a hashref constructor starts with just a bare {.
Technically speaking the { } in the dereference syntax form an actual block of code:
print ${
print "one\n"; # yeah, I just put a statement in the middle of an expression
print "two\n";
["three"] # the last expression in this block is implicitly returned
# (and dereferenced by the surrounding $ [0] construct outside)
}[0], "\n";
For (hopefully) obvious reasons, no one actually does this in real code.
The syntax is
my $lastindex = $#$array_reference;
which assigns to $lastindex the index of the last element of the anonymous array which reference is in the variable $array_reference.
The code
my #ary = { $ra }; # works but you get a warning
doesn't throw "an error" but rather a warning. In other words, you do get #ary with one element, a reference to an anonymous hash. However, a hash need have an even number of elements so you also get a warning that that isn't so.
Your last attempt dereferences the array with #{$array_reference} -- which returns a list, not an array variable. A "list" is a fleeting collection of scalars in memory (think of copying scalars on stack to go elsewhere); there is no notion of "index" for such a thing. For this reason a $##{$ra} isn't even parsed as intended and is a syntax error.
The syntax $#ary works only with a variable #ary, and then there is the $#$arrayref syntax. You can in general write $#{$arrayref} since the curlies allow for an arbitrary expression that evaluates to an array reference but there is no reason for that since you do have a variable with an array reference.
I'd agree readily that much of this syntax takes some getting-used-to, to put it that way.
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()];
Here is the situation I am facing...
$perl_scalar = decode_json( encode ('utf8',$line));
decode_json returns a reference. I am sure this is an array. How do I find the size of $perl_scalar?? As per Perl documentation, arrays are referenced using #name. Is there a workaround?
This reference consist of an array of hashes. I would like to get the number of hashes.
If I do length($perl_scalar), I get some number which does not match the number of elements in array.
That would be:
scalar(#{$perl_scalar});
You can get more information from perlreftut.
You can copy your referenced array to a normal one like this:
my #array = #{$perl_scalar};
But before that you should check whether the $perl_scalar is really referencing an array, with ref:
if (ref($perl_scalar) eq "ARRAY") {
my #array = #{$perl_scalar};
# ...
}
The length method cannot be used to calculate length of arrays. It's for getting the length of the strings.
You can also use the last index of the array to calculate the number of elements in the array.
my $length = $#{$perl_scalar} + 1;
$num_of_hashes = #{$perl_scalar};
Since you're assigning to a scalar, the dereferenced array is evaluated in a scalar context to the number of elements.
If you need to force scalar context then do as KARASZI says and use the scalar function.
You can see the entire structure with Data::Dumper:
use Data::Dumper;
print Dumper $perl_scalar;
Data::Dumper is a standard module that is installed with Perl. For a complete list of all the standard pragmatics and modules, see perldoc perlmodlib.
Let us say that we have following array:
my #arr=('Jan','Feb','Mar','Apr');
my #arr2=#arr[0..2];
How can we do the same thing if we have array reference like below:
my $arr_ref=['Jan','Feb','Mar','Apr'];
my $arr_ref2; # How can we do something similar to #arr[0..2]; using $arr_ref ?
To get a slice starting with an array reference, replace the array name with a block containing the array reference. I've used whitespace to spread out the parts, but it's still the same thing:
my #slice = # array [1,3,2];
my #slice = # { $aref } [1,3,2];
If the reference inside the block is a simple scalar (so, not an array or hash element or a lot of code), you can leave off the braces:
my #slice = #$aref[1,3,2];
Then, if you want a reference from that, you can use the anonymous array constructor:
my $slice_ref = [ #$aref[1,3,2] ];
With the new post-dereference feature (experimental) in v5.20,
use v5.20;
use feature qw(postderef);
no warnings qw(experimental::postderef);
my #slice = $aref->#[1,3,2];
Just slice the reference (the syntax is similar to dereferencing it, see the comments), and then turn the resulting list back into a ref:
my $arr_ref2=[#$arr_ref[0..2]];
my $arr_ref2 = [ #$arr_ref[0..2] ];
In this snippet:
find( sub {
print "found " . $File::Find::name . "\n";
}, ("."));
What type will the (".") be? Array or scalar?
Let's take a look at the parameters for File::Find::find. The documentation says:
find(\&wanted, #directories_to_search);
Let's think of the find() function written like this:
sub find
{
my ($wanted, #directories_to_search) = #_;
...
}
What you need to realize is that the parameters passed to a function are already in list context (a list of scalars): that's the special variable #_. So when you call find(), the first argument is assigned to $wanted, treated as a coderef (a reference is just a type of scalar). The next variable being assigned to is an array. When you assign a list to an array, the array is "greedy" and takes all values from the list.
So when you assign #_ to ($wanted, #directories_to_search), and all remaining arguments are assigned to #directories_to_search (an array of scalars).
Now let's go back to your code. At the highest level, you're calling find() by passing a list consisting of two terms:
the anonymous coderef sub { ... }
".": a string of one character in length.
That's like this:
my ($wanted, #directories_to_search) = (sub { ... }, ".");
So find() receives those arguments as I described above: the anonymous coderef is the first argument, and #directories_to_search gobbles the rest:
my $wanted = sub { ... };
my #directories_to_search = ".";
I'm not really sure why you are asking the question (what type is the (".") term), but you can make the call to find() as you have written it above, or you can remove the extra set of parentheses (they don't add anything).
Read MJD on context.