Confused by local variables and methods in Perl - perl

I've got the following Perl code:
my $wantedips;
# loop through the interfaces
foreach (#$interfaces) {
# local variable called $vlan
my $vlan = $_->{vlan};
# local variable called $cidr
my $cidr = $_->{ip} ."/".$nnm->bits();
# I dont understand this next bit.
# As a rubyist, it looks like a method called $cidr is being called on $wantedips
# But $cidr is already defined as a local variable.
# Why the spooky syntax? Why is $cidr passed as a method to $wantedips?
# what does ->{} do in PERL? Is it some kind of hash syntax?
$wantedips->{$cidr} = $vlan;
# break if condition true
next if ($ips->{$cidr} == $vlan);
# etc
}
The part I don't get is in my comments. Why is $cidr passed to $wantedips, when both are clearly defined as local variables? I'm a rubyist and this is really confusing. I can only guess that $xyz->{$abc}="hello" creates a hash of some sort like so:
$xyz => {
$abc => "hello"
}
I'm new to Perl as you can probably tell.

I don't understand why you are comfortable with
my $vlan = $_->{vlan}
but then
$wantedips->{$cidr} = $vlan
gives you trouble? Both use the same syntax to access hash elements using a hash reference.
The indirection operator -> is used to apply keys, indices, or parameters to a reference value, so you access elements of a hash by its reference with
$href->{vlan}
elements of an array by its reference with
$aref->[42]
and call a code reference with
$cref->(1, 2, 3)
As a convenience, and to make code cleaner, you can remove the indirection operator from the sequences ]->[ and }->{ (and any mixture of brackets and braces). So if you have a nested data structure you can write
my $name = $system->{$ip_address}{name}[2]
instead of
my $name = $system->{$ip_address}->{name}->[2]

#I dont understand this next bit.
$wantedips->{$cidr} = $vlan;
$wantedips is a scalar, specifically it is a hashref (a reference to a hash).
The arrow gets something from inside the reference.
{"keyname"} is how to access a particular key in a hash.
->{"keyname"} is how you access a particular key in a hash ref
$cidr is also a scalar, in this case it is a string.
->{$cidr} accesses a key from a hash ref when the key name is stored in a string.
So to put it all together:
$wantedips->{$cidr} = $vlan; means "Assign the value of $vlan to the key described by the string stored in $cidr on the hash referenced by $wantedips.
I can only guess that $xyz->{$abc}="hello" creates a hash of some sort
like.
Let's break this down to a step by step example that strips out the loops and other bits not directly associated with the code in question.
# Create a hash
my %hash;
# Make it a hashref
my $xyz = \%hash;
# (Those two steps could be done as: my $xyz = {})
# Create a string
my $abc = "Hello";
# Use them together
$xyz->{$abc} = "world";
# Look at the result:
use Data::Dump;
Data::Dump::ddx($xyz);
# Result: { Hello => "world" }

Related

Is it possible to use hash, array, scalar with the same name in Perl?

I'm converting perl script to python.
I haven't used perl language before so many things in perl confused me.
For example, below, opt was declared as a scalar first but declared again as a hash. %opt = ();
Is it possible to declare a scalar and a hash with the same name in perl?
As I know, foreach $opt (#opts) means that scalar opt gets values of array opts one by one. opt is an array at this time???
In addition, what does $opt{$opt} mean?
opt outside $opt{$opt} is a hash and opt inside $opt{$opt} is a scalar?
I'm so confused, please help me ...
sub ParseOptions
{
local (#optval) = #_;
local ($opt, #opts, %valFollows, #newargs);
while (#optval) {
$opt = shift(#optval);
push(#opts,$opt);
$valFollows{$opt} = shift(#optval);
}
#optArgs = ();
%opt = ();
arg: while (defined($arg = shift(#ARGV))) {
foreach $opt (#opts) {
if ($arg eq $opt) {
push(#optArgs, $arg);
if ($valFollows{$opt}) {
if (#ARGV == 0) {
&Usage();
}
$opt{$opt} = shift(#ARGV);
push(#optArgs, $opt{$opt});
} else {
$opt{$opt} = 1;
}
next arg;
}
}
push(#newargs,$arg);
}
#ARGV = #newargs;
}
In Perl types SCALAR, ARRAY, and HASH are distinguished by the leading sigil in the variable name, $, #, and % respectively, but otherwise they may bear the same name. So $var and #var and %var are, other than belonging to the same *var typeglob, completely distinct variables.
A key for a hash must be a scalar, let's call it $key. A value in a hash must also be a scalar, and the one corresponding to $key in the hash %h is $h{$key}, the leading $ indicating that this is now a scalar. Much like an element of an array is a scalar, thus $ary[$index].
In foreach $var (#ary) the scalar $var does not really "get values" of array elements but rather aliases them. So if you change it in the loop you change the element of the array.
(Note, you have the array #opts, not #opt.)
A few comments on the code, in the light of common practices in modern Perl
One must always have use warnings; on top. The other one that is a must is use strict, as it enforces declaration of variables with my (or our), promoting all kinds of good behavior. This restricts the scope of lexical (my) variables to the nearest block enclosing the declaration
A declaration may be done inside loops as well, allowing while (my $var = EXPR) {} and foreach my $var (LIST) {}, and then $var is scoped to the loop's block (and is also usable in the rest of the condition)
The local is a different beast altogether, and in this code those should be my instead
Loop labels like arg: are commonly typed in block capitals
The & in front of a function name has rather particular meanings† and is rarely needed. It is almost certainly not needed in this code
Assignment of empty list like my #optArgs = () when the variable is declared (with my) is unneeded and has no effect (with a global #name it may be needed to clear it from higher scope)
In this code there is no need to introduce variables first since they are global and thus created the first time they are used, much like in Python – Unless they are used outside of this sub, in which case they may need to be cleared. That's the thing with globals, they radiate throughout all code
Except for the last two these are unrelated to your Python translation task, for this script.
† It suppresses prototypes; informs interpreter (at runtime) that it's a subroutine and not a "bareword", if it hasn't been already defined (can do that with () after the name); ensures that the user-defined sub is called, if there is a builtin of the same name; passes the caller's #_ (when without parens, &name); in goto &name and defined ...
See, for example, this post and this post
First, to make it clear, in perl, as in shell, you could surround variable names in curly brackets {} :
${bimbo} and $bimbo are the same scalar variable.
#bimbo is an array pointer ;
%bimbo is a hash pointer ;
$bimbo is a scalar (unique value).
To address an array or hash value, you will have to use the '$' :
$bimbo{'index'} is the 'index' value of hash %bimbo.
If $i contains an int, such as 1 for instance,
$bimbo[$i] is the second value of the array #bimbo.
So, as you can see, # or % ALWAYS refers to the whole array, as $bimbo{} or $bimbo[] refers to any value of the hash or array.
${bimbo[4]} refers to the 5th value of the array #bimbo ; %{bimbo{'index'}} refers to the 'index' value of array %bimbo.
Yes, all those structures could have the same name. This is one of the obvious syntax of perl.
And, euhm… always think in perl as a C++ edulcored syntax, it is simplified, but it is C.

Does iterating over a hash reference require implicitly copying it in perl?

Lets say I have a large hash and I want to iterate over the contents of it contents. The standard idiom would be something like this:
while(($key, $value) = each(%{$hash_ref})){
///do something
}
However, if I understand my perl correctly this is actually doing two things. First the
%{$hash_ref}
is translating the ref into list context. Thus returning something like
(key1, value1, key2, value2, key3, value3 etc)
which will be stored in my stacks memory. Then the each method will run, eating the first two values in memory (key1 & value1) and returning them to my while loop to process.
If my understanding of this is right that means that I have effectively copied my entire hash into my stacks memory only to iterate over the new copy, which could be expensive for a large hash, due to the expense of iterating over the array twice, but also due to potential cache hits if both hashes can't be held in memory at once. It seems pretty inefficient. I'm wondering if this is what really happens, or if I'm either misunderstanding the actual behavior or the compiler optimizes away the inefficiency for me?
Follow up questions, assuming I am correct about the standard behavior.
Is there a syntax to avoid copying of the hash by iterating over it values in the original hash? If not for a hash is there one for the simpler array?
Does this mean that in the above example I could get inconsistent values between the copy of my hash and my actual hash if I modify the hash_ref content within my loop; resulting in $value having a different value then $hash_ref->($key)?
No, the syntax you quote does not create a copy.
This expression:
%{$hash_ref}
is exactly equivalent to:
%$hash_ref
and assuming the $hash_ref scalar variable does indeed contain a reference to a hash, then adding the % on the front is simply 'dereferencing' the reference - i.e. it resolves to a value that represents the underlying hash (the thing that $hash_ref was pointing to).
If you look at the documentation for the each function, you'll see that it expects a hash as an argument. Putting the % on the front is how you provide a hash when what you have is a hashref.
If you wrote your own subroutine and passed a hash to it like this:
my_sub(%$hash_ref);
then on some level you could say that the hash had been 'copied', since inside the subroutine the special #_ array would contain a list of all the key/value pairs from the hash. However even in that case, the elements of #_ are actually aliases for the keys and values. You'd only actually get a copy if you did something like: my #args = #_.
Perl's builtin each function is declared with the prototype '+' which effectively coerces a hash (or array) argument into a reference to the underlying data structure.
As an aside, starting with version 5.14, the each function can also take a reference to a hash. So instead of:
($key, $value) = each(%{$hash_ref})
You can simply say:
($key, $value) = each($hash_ref)
No copy is created by each (though you do copy the returned values into $key and $value through assignment). The hash itself is passed to each.
each is a little special. It supports the following syntaxes:
each HASH
each ARRAY
As you can see, it doesn't accept an arbitrary expression. (That would be each EXPR or each LIST). The reason for that is to allow each(%foo) to pass the hash %foo itself to each rather than evaluating it in list context. each can do that because it's an operator, and operators can have their own parsing rules. However, you can do something similar with the \% prototype.
use Data::Dumper;
sub f { print(Dumper(#_)); }
sub g(\%) { print(Dumper(#_)); } # Similar to each
my %h = (a=>1, b=>2);
f(%h); # Evaluates %h in list context.
print("\n");
g(%h); # Passes a reference to %h.
Output:
$VAR1 = 'a'; # 4 args, the keys and values of the hash
$VAR2 = 1;
$VAR3 = 'b';
$VAR4 = 2;
$VAR1 = { # 1 arg, a reference to the hash
'a' => 1,
'b' => 2
};
%{$h_ref} is the same as %h, so all of the above applies to %{$h_ref} too.
Note that the hash isn't copied even if it is flattened. The keys are "copied", but the values are returned directly.
use Data::Dumper;
my %h = (abc=>"def", ghi=>"jkl");
print(Dumper(\%h));
$_ = uc($_) for %h;
print(Dumper(\%h));
Output:
$VAR1 = {
'abc' => 'def',
'ghi' => 'jkl'
};
$VAR1 = {
'abc' => 'DEF',
'ghi' => 'JKL'
};
You can read more about this here.

Why is 1 assigned to a hash element?

Could any one explain what this statement does in Perl
$type{$_->{brand}} = 1;
I could understand that the hash %type has a key brand holding the reference to another hash brand and 1 is assigned to it
what does it mean??!!! when it is assigned as 1?
package SillyFunction;
sub group_products {
my $products = shift;
my %brand_type = ();
my $grouped_products = [];
foreach (#{$products}) {
$brand_type{ $_->{brand} } ||= {};
$brand_type{ $_->{brand} }->{ $_->{type} } = 1;
}
foreach (sort keys %brand_type) {
my $brand = $_;
foreach (sort keys %{ $brand_type{$brand} }) {
push(#{$grouped_products}, { brand => $brand, type => $_ });
}
}
$grouped_products;
}
1;
The code
$type{$_->{brand}} = 1;
means:
We have a variable of the type hash, named %hash.
The topic variable $_ contains a reference to a hash.
We access the entry called brand in the hash referenced by $_. We remember this value.
We access the entry with the name we just remembered in the hash named %hash.
Hash elements are lvalues, i.e. something can be assigned to them.
We assign the number 1 into the hash slot we just accessed.
Points to note:
In Perl, a hash is a data structure. Other languages know this as an associative array. It maps strings to scalar values.
A hash function calculates a characteristic number for a given string. The hash data structure uses such a function internally, and in a way inaccessible from Perl. Hash functions are also important in cryptography.
The = operator assigns the thing on the right to the thing on the left.
That line of code has not a single keyword, only variables (%type, $_), constants ('brand', 1) and operators ({...}, ->, =, ;).
Here is the code you posted in your comment, annotated with comments:
# Declare a namespace "SillyFunction".
# This affects the full names of the subroutines, and some variables.
package SillyFunction;
# Declare a sub that takes one parameter.
sub group_products {
my $products = shift;
my %brand_type = (); # %brand_type is an empty hash.
my $grouped_products = []; # $grouped_products is a reference to an array
# loop through the products.
# The #{...} "dereferences" an arrayref to an ordinary array
# The current item is in the topic variable $_
foreach (#{$products}) {
# All the items in $products are references to hashes.
# The hashes have keys "brand" and "type".
# If the entry if %brand_type with the name of $_->{brand} is false,
# Then we assign an empty hashref.
# This is stupid (see discussion below)
$brand_type{$_->{brand}} ||= {};
# We access the entry names $_->{brand}.
# We use that value as a hashref, and access the entry $_->{type} in there.
# We then assign the value 1 to that slot.
$brand_type{$_->{brand}}->{$_->{type}} = 1;
}
# We get the names of all entries of %brand_type with the keys function
# We sort the names alphabetically.
# The current key is in $_
foreach (sort keys %brand_type) {
# We assign the current key to the $brand variable.
# This is stupid.
my $brand = $_;
# We get all the keys of the hash referenced by $brand_type{$brand}
# And sort that again.
# The current key is in $_
foreach (sort keys %{$brand_type{$brand}}) {
# We dereference the ordinary array from the arrayref $grouped_products.
# We add a hashref to the end that contains entries for brand and type
push(#{$grouped_products}, { brand => $brand, type => $_});
}
}
# We implicitly return the arrayref containing all brands and types.
$grouped_products;
}
# We return a true value to signal perl that this module loaded all right.
1;
What does this code do? It takes all products (a product is a hashref containing a field for brand and type), and sorts them primarily by brand, secondarily by type, in alphabetic, ascending order.
While doing so, the author produced horrible code. Here is what could have gone better:
He uses an arrayref instead of an array. It would have been easier to just use an array, and return a reference to that:
my #grouped_products;
push #grouped_products, ...;
return \#grouped_products; # reference operator \
At some point, an hashref is assigned. This is unneccessary, as Perl autovivicates undefined values that you use as a hash or array reference. That complete line is useless. Also, it is only assigned if that value is false. What the author probably wanted is to assign if that value is undefined. The defined-or operator // could have been used here (only since perl5 v10 or later).
A hash of hashes is built. This is wasteful. A hash of an array would have been better.
If one loops over values with for or foreach, the current item doesn't have to be assigned to the cryptic $_. Instead, a loop variable can be specified: foreach my $foo (#bar). The default behaviour of foreach is similar to foreach local $_ (#bar).
Implicit returns are bad.
Here is a piece of code that implements the same subroutine, but more perlish — remember, we just wanted to sort the products (assuming they already are unique)
sub group_products {
my ($products) = #_;
my #grouped =
# sort by brand. If that is a draw, sort by type.
sort { $a->{brand} cmp $b->{brand} or $a->{type} cmp $b->{type} }
map { +{%$_} } # make a copy.
#$products; # easy dereference
return \#grouped;
}
Explanation: This code is largely self-documenting. The sort function takes a block that has to return a number: Either negative for “$a is smaller than $b”, zero for “$a and $b are equal”, or positive for “$a is larger than $b”.
The cmp operator compare the operands lexigraphically. If the brands are different, then we don't have to compare the types. If the brands are the same, then the first cmp returns 0, which is a false value. Therefore, the second comparision (type) is executed, and that value returned. This is standard Perl idiom for sorting by primary and secondary key.
The sort and map cascade executes from right/bottom to left/top.
If the uniqueness is not guaranteed, something like this would work better:
use List::MoreUtils qw/uniq/;
sub group_products {
my ($products) = #_;
my %grouping;
push #{ $grouping{ $_->{brand} } }, $_->{type} for #$products;
my #grouped;
for my $brand (sort keys %grouping) {
push #grouped, +{brand => $brand, type => $_} for sort uniq #{ $grouping{$brand} };
}
return \#grouped;
}
Explanation: We define a %grouping hash (to be filled). For each product, we add the type of that product to the arrayref of the appropriate brand in the grouping hash. That is, we collect all types for each brand. We define an array of all grouped products (to be filled). We iterate through all brands in alphabetical order, and then iterate through all unique products of that brand in alphabetical order. For each of these brand/type combinations, we add a new hashref to the grouped products. The uniq function is imported from the excellent List::MoreUtils module. We return a reference to the array of grouped products.

Confusion about proper usage of dereference in Perl

I noticed the other day that - while altering values in a hash - that when you dereference a hash in Perl, you actually are making a copy of that hash. To confirm I wrote this quick little script:
#! perl
use warnings;
use strict;
my %h = ();
my $hRef = \%h;
my %h2 = %{$hRef};
my $h2Ref = \%h2;
if($hRef eq $h2Ref) {
print "\n\tThey're the same $hRef $h2Ref";
}
else {
print "\n\tThey're NOT the same $hRef $h2Ref";
}
print "\n\n";
The output:
They're NOT the same HASH(0x10ff6848) HASH(0x10fede18)
This leads me to realize that there could be spots in some of my scripts where they aren't behaving as expected. Why is it even like this in the first place? If you're passing or returning a hash, it would be more natural to assume that dereferencing the hash would allow me to alter the values of the hash being dereferenced. Instead I'm just making copies all over the place without any real need/reason to beyond making syntax a little more obvious.
I realize the fact that I hadn't even noticed this until now shows its probably not that big of a deal (in terms of the need to go fix in all of my scripts - but important going forward). I think its going to be pretty rare to see noticeable performance differences out of this, but that doesn't alter the fact that I'm still confused.
Is this by design in perl? Is there some explicit reason I don't know about for this; or is this just known and you - as the programmer - expected to know and write scripts accordingly?
The problem is that you are making a copy of the hash to work with in this line:
my %h2 = %{$hRef};
And that is understandable, since many posts here on SO use that idiom to make a local name for a hash, without explaining that it is actually making a copy.
In Perl, a hash is a plural value, just like an array. This means that in list context (such as you get when assigning to a hash) the aggregate is taken apart into a list of its contents. This list of pairs is then assembled into a new hash as shown.
What you want to do is work with the reference directly.
for (keys %$hRef) {...}
for (values %$href) {...}
my $x = $href->{some_key};
# or
my $x = $$href{some_key};
$$href{new_key} = 'new_value';
When working with a normal hash, you have the sigil which is either a % when talking about the entire hash, a $ when talking about a single element, and # when talking about a slice. Each of these sigils is then followed by an identifier.
%hash # whole hash
$hash{key} # element
#hash{qw(a b)} # slice
To work with a reference named $href simply replace the string hash in the above code with $href. In other words, $href is the complete name of the identifier:
%$href # whole hash
$$href{key} # element
#$href{qw(a b)} # slice
Each of these could be written in a more verbose form as:
%{$href}
${$href}{key}
#{$href}{qw(a b)}
Which is again a substitution of the string '$href' for 'hash' as the name of the identifier.
%{hash}
${hash}{key}
#{hash}{qw(a b)}
You can also use a dereferencing arrow when working with an element:
$hash->{key} # exactly the same as $$hash{key}
But I prefer the doubled sigil syntax since it is similar to the whole aggregate and slice syntax, as well as the normal non-reference syntax.
So to sum up, any time you write something like this:
my #array = #$array_ref;
my %hash = %$hash_ref;
You will be making a copy of the first level of each aggregate. When using the dereferencing syntax directly, you will be working on the actual values, and not a copy.
If you want a REAL local name for a hash, but want to work on the same hash, you can use the local keyword to create an alias.
sub some_sub {
my $hash_ref = shift;
our %hash; # declare a lexical name for the global %{__PACKAGE__::hash}
local *hash = \%$hash_ref;
# install the hash ref into the glob
# the `\%` bit ensures we have a hash ref
# use %hash here, all changes will be made to $hash_ref
} # local unwinds here, restoring the global to its previous value if any
That is the pure Perl way of aliasing. If you want to use a my variable to hold the alias, you can use the module Data::Alias
You are confusing the actions of dereferencing, which does not inherently create a copy, and using a hash in list context and assigning that list, which does. $hashref->{'a'} is a dereference, but most certainly does affect the original hash. This is true for $#$arrayref or values(%$hashref) also.
Without the assignment, just the list context %$hashref is a mixed beast; the resulting list contains copies of the hash keys but aliases to the actual hash values. You can see this in action:
$ perl -wle'$x={"a".."f"}; for (%$x) { $_=chr(ord($_)+10) }; print %$x'
epcnal
vs.
$ perl -wle'$x={"a".."f"}; %y=%$x; for (%y) { $_=chr(ord($_)+10) }; print %$x; print %y'
efcdab
epcnal
but %$hashref isn't acting any differently than %hash here.
No, dereferencing does not create a copy of the referent. It's my that creates a new variable.
$ perl -E'
my %h1; my $h1 = \%h1;
my %h2; my $h2 = \%h2;
say $h1;
say $h2;
say $h1 == $h2 ?1:0;
'
HASH(0x83b62e0)
HASH(0x83b6340)
0
$ perl -E'
my %h;
my $h1 = \%h;
my $h2 = \%h;
say $h1;
say $h2;
say $h1 == $h2 ?1:0;
'
HASH(0x9eae2d8)
HASH(0x9eae2d8)
1
No, $#{$someArrayHashRef} does not create a new array.
If perl did what you suggest, then variables would get aliased very easily, which would be far more confusing. As it is, you can alias variables with globbing, but you need to do so explicitly.

Should I use $_[0] or copy the argument list in Perl?

If I pass a hash to a sub:
parse(\%data);
Should I use a variable to $_[0] first or is it okay to keep accessing $_[0] whenever I want to get an element from the hash? clarification:
sub parse
{ $var1 = $_[0]->{'elem1'};
$var2 = $_[0]->{'elem2'};
$var3 = $_[0]->{'elem3'};
$var4 = $_[0]->{'elem4'};
$var5 = $_[0]->{'elem5'};
}
# Versus
sub parse
{ my $hr = $_[0];
$var1 = $hr->{'elem1'};
$var2 = $hr->{'elem2'};
$var3 = $hr->{'elem3'};
$var4 = $hr->{'elem4'};
$var5 = $hr->{'elem5'};
}
Is the second version more correct since it doesn't have to keep accessing the argument array, or does Perl end up interpereting them the same way anyhow?
In this case there is no difference because you are passing reference to hash. But in case of passing scalar there will be difference:
sub rtrim {
## remove tailing spaces from first argument
$_[0] =~ s/\s+$//;
}
rtrim($str); ## value of the variable will be changed
sub rtrim_bugged {
my $str = $_[0]; ## this makes a copy of variable
$str =~ s/\s+$//;
}
rtrim($str); ## value of the variable will stay the same
If you're passing hash reference, then only copy of reference is created. But the hash itself will be the same. So if you care about code readability then I suggest you to create a variable for all your parameters. For example:
sub parse {
## you can easily add new parameters to this function
my ($hr) = #_;
my $var1 = $hr->{'elem1'};
my $var2 = $hr->{'elem2'};
my $var3 = $hr->{'elem3'};
my $var4 = $hr->{'elem4'};
my $var5 = $hr->{'elem5'};
}
Also more descriptive variable names will improve your code too.
For a general discussion of the efficiency of shift vs accessing #_ directly, see:
Is there a difference between Perl's shift versus assignment from #_ for subroutine parameters?
Is 'shift' evil for processing Perl subroutine parameters?
As for your specific code, I'd use shift, but simplify the data extraction with a hash slice:
sub parse
{
my $hr = shift;
my ($var1, $var2, $var3, $var4, $var5) = #{$hr}{qw(elem1 elem2 elem3 elem4 elem5)};
}
I'll assume that this method does something else with these variables that makes it worthwhile to keep them in separate variables (perhaps the hash is read-only, and you need to make some modifications before inserting them into some other data?) -- otherwise why not just leave them in the hashref where they started?
You are micro-optimizing; try to avoid that. Go with whatever is most readable/maintainable. Usually this would be the one where you use a lexical variable, since its name indicates its purpose...but if you use a name like $data or $x this obviously doesn't apply.
In terms of the technical details, for most purposes you can estimate the time taken by counting the number of basic ops perl will use. For your $_[0], an element lookup in a non-lexical array variable takes multiple ops: one to get the glob, one to get the array part of the glob, one or more to get the index (just one for a constant), and one to look up the element. $hr, on the other hand is a single op. To cater to direct users of #_, there's an optimization that reduces the ops for $_[0] to a single combined op (when the index is between 0 and 255 inclusive), but it isn't used in your case because the hash-deref context requires an additional flag on the array element lookup (to support autovivification) and that flag isn't supported by the optimized op.
In summary, using a lexical is going to be both more readable and (if you using it more than once) imperceptibly faster.
My rule is that I try not to use $_[0] in subroutines that are longer than a couple of statements. After that everything gets a user-defined variable.
Why are you copying all of the hash values into variables? Just leave them in the hash where they belong. That's a much better optimization than the one you are thinking about.
Its the same although the second is more clear
Since they work, both are fine, the common practice is to shift off parameters.
sub parse { my $hr = shift; my $var1 = $hr->{'elem1'}; }