Difference between $map{$string} and $map->{$string} in Perl - perl

I have a map structure in Perl, that I'm getting from some utility. The dump of which looks like this:
$VAR1 = {
'A0' => 'me_one',
'A2' => 'me_two',
'A6' => 'me_six'
}
I want to search if a particular key exists in the map. Say I would like to know if A4 is in the map.
Now if I use if (exists $map{'A4'}), I get an error during build, at $map{.
And if I use if (exists $map->{'A4'}), I get no error, and I get the desired result. However everywhere I search on the internet, to check if a key exists in a map, the syntax in Perl is if (exists $map{key})
Now my inference is that what I get from utility is not a map, though still looks like a map to me from the dump. Any one has an idea what's going on? Thank you.
Edit: Thanks to #raina77ow's answer. Adding this to further his explanation.
my %map;
print $map{key};
my $map_ref = \%map; # The reference was what the utility was returning
print $map_ref->{key};

The $map{key} line is used when you address a specific element of hash %map. For example:
my %map = (
a => 'a',
b => 'b'
);
print $map{a}; # 'a'
The $map->{key} line is used when you address a specific element of hashref $map. -> operator is used specifically to 'deference' a reference.
my $map_ref = {
a => 'a',
b => 'b'
};
print $map_ref->{a}; # 'a'
Note that in the first case the regular parenthesis are used, in the second case it's curly brackets (to define so-called anonymous hash).

Related

How to let Perl recognize both lower and uppercase input?

I'm currently trying to figure out how I can make my perl script accept both the lowercase and uppercase variant of a letter.
For Example.
my %channels = (a => 'test', b => 'test2', c => 'test3', d => 'test4', e => 'test5', f => 'test6', g => 'test7');
So when I want to enter test I can either do a or A and it will accept it
To Sum up the problem:
When running the script I ran into an issue where you had to input a if you wanted test. This is all fine to me but other people wanted the option to do capital A instead. I am trying to give them the option to do either.
Thanks All
For your hash keys (single alphabet as a key) try the logical defined operator.
// => logical defined operator. If the left hand side is true give the result else if evaluate the right side.
print $channels{$input} // $channels{lc($input)};
One simple solution for your input
print $channels{lc($input)};
If the input is uppercase it will convert to lowercase. Don't get worry about lowercase characters.
It is not fully clear what your requirement is but from the example it looks like you are asking for a hash which is case insensitive regarding the keys, i.e. that $hash{foo}, $hash{FoO} etc all result in the same value.
This can be implemented with tied hashes by defining appropriate FETCH,STORE and DELETE methods for the hash. And there are already implementations which do this, like Hash::Case.
Of course you could also simply normalize all keys (lower case, upper case etc) before accessing the hash.
I would keep all the hash keys lower case and convert the input value keys to lower case:
for my $inputKey ('a', 'A', 'b', 'B') {
print $channels{lc($inputKey)}, "\n";
}
With a regex it's not shorter but another way to solve it:
my %hash = {a => 'test', b => 'test2'};
my $read_input;
foreach my $key (keys %hash){
if($key =~ /${read_input}/i){ #note the i for 'ignore case'
print $hash{$key};
}
}
You basically iterate through the keys of your hash and compare them against the input. If you found the right one you can print the value.
But nevertheless: You may just convert every input to lower case and then access the hash.

Unable to properly merge hashes

I currently have the following
# $dog, $cat, $rat are all hash refs
my %rethash = ('success' => 'Your Cool');
my %ref ={ 'dog' => $dog, 'cat' => $cat, 'mouse' => $rat,
'chicken' => '' };
my $perlobj = ( \%ref,\%rethash );
When $perlobj is dumped this is the result
$VAR1 = {
'success' => 'Your Cool'
};
However when warnings are enabled I get the following message
Useless use of reference constructor in void context at ..
I realize there is something terribly wrong with how %ref is assigned using {}, What is wrong with this code? I can't seem to get rid of this warning....
EDIT:
Ok I think I figured out whats going on,
my $perlobj = ( \%ref,\%rethash );
This does not merge but results in $perlobj becoming a reference to %rethash, this is obvious after reading your responses.
What RobEarl is saying is correct. I'll give an explanation of that and add some more stuff.
Your variable name %ref and the fact that you are using {} kinda implies you want a reference here.
Let's take a look what value we will have in %ref. Consider this example.
use strict; use warnings;
use Data::Printer;
my %foo = { key => 'value' };
p %foo;
This will throw a warning Reference found where even-sized list expected on my Perl 5.20.2. The output will be:
{
HASH(0x7e33c0) undef
}
It's a hash with a hashref as the key and undef as a value. HASH(0x07e33c0) is what you get when you look at a hash reference without dereferencing it. (The {} are there because Data::Printer converts the hash to a hashref).
Back to your code, the correct sigil for a reference is $. It does not matter what kind of reference it is. The reference is always a scalar (a pointer to the place in memory where the hash/array/something) is stored.
my $ref = {
dog => $dog,
cat => $cat,
mouse => $rat,
chicken => '', # maybe this should be undef?
};
Now you've got a hashref with the values of $dog, $cat, $rat and an empty string.
Now you're assigning a variable named $perlobj, which implies it's an object. Instead you are assigning a scalar variable (the $ makes it a scalar) with a list. If you do that, Perl will only assign the right-most value to the variable.
my $foo = (1, 2, 3); # $foo will be 3 and there's a warning
You are assigning a list of two references. The first one is disregarded and only \$rethash gets assigned. That works because conveniently, $perlobj is a scalar, and references are also scalars. So now $perlobj is a reference of %rethash. That's why your Data::Dumper output looks like %rethash.
I'm not sure what you want to do, so I cannot really help you with that. I suggest you read up on some stuff.
perlreftut is useful to learn how references work
If you want to do Object Oriented Programming, check out Moose
It might also be useful to just go get a book to learn a bit more about basic Perl. Learning Perl by Randal L. Schwartz and Beginning Perl by Curtis Poe are both very good for that
You are taking a list of hash references and assigning them to a scalar
my $perlobj = ( \%ref, \%rethash ); # same as $perlobj = \%rethash
Instead you want to take a reference to a merger of hashes
my $perlobj = { %ref, %rethash };

Why does this map block contain an apparently useless +?

While browsing the source code I saw the following lines:
my #files_to_keep = qw (file1 file2);
my %keep = map { + $_ => 1 } #files_to_keep;
What does the + do in this code snippet? I used Data::Dumper to see whether taking out the plus sign does anything, but the results were the same:
$ perl cleanme.pl
$VAR1 = {
'file1' => 1,
'file2' => 1
};
This is used to prevent a parsing problem. The plus symbol forces the interpreter to behave like a normal block and not an expression.
The fear is that perhaps you are trying to create a hashreference using the other (expression) formulation of map like so.
#array_of_hashrefs = map { "\L$_" => 1 }, #array
Notice the comma. Then if the parser guesses that you are doing this given the statement in the OP there will a syntax error for missing the comma! To see the difference try quoting "$_". For whatever reason, the parser takes this as enough to trigger the expression behavior.
Yes its an oddity. Therefore many extra-paranoid Perl programmers toss in the extra plus sign more often than needed (me included).
Here are the examples from the map documentation.
%hash = map { "\L$_" => 1 } #array # perl guesses EXPR. wrong
%hash = map { +"\L$_" => 1 } #array # perl guesses BLOCK. right
%hash = map { ("\L$_" => 1) } #array # this also works
%hash = map { lc($_) => 1 } #array # as does this.
%hash = map +( lc($_) => 1 ), #array # this is EXPR and works!
%hash = map ( lc($_), 1 ), #array # evaluates to (1, #array)
For a fun read (stylistically) and a case where the parser gets it wrong read this: http://blogs.perl.org/users/tom_wyant/2012/01/the-case-of-the-overloaded-curlys.html
The unary-plus operator simply returns its operand unchanged. Adding one doesn't even change the context.
In the example you gave, it is completely useless. But there are situations where it is useful to make the next token something that's undeniably an operator.
For example, map has two syntaxes.
map EXPR, LIST
and
map BLOCK LIST
A block starts with {, but so can an expression. For example, { } can be a block or a hash constructor.
So how can map tell the difference? It guesses. Which means it's sometimes wrong.
One occasion where is guesses wrong is the following:
map { $_ => 1 }, #list
You can prod it in to guessing correctly using + or ;.
map {; ... # BLOCK
map +{ ... # EXPR
So in this case, you could use
map +{ foo => $_ }, #list
Note that you could also use the following:
map({ foo => $_ }, #list)
Another example is when you omit the parens around arguments, and the first argument expression starts with a paren.
print ($x+$y)*2; # Same as: 2 * print($x+$y)
It can be fixed using
print +($x+$y)*2;
But why pile on a hack just to avoid parens? I prefer
print(($x+$y)*2);

What happens when you put an array on the right side of a => operator?

This might seem like a stupid question but it's been a long day. I'm an adapting some Perl code for another use and I ran across this syntax:
my #request;
#... fill the array with stuff...
my $reply = $service->call('requestMessage' => #request, $header);
That method call seems implausible, if => is just a special kind of comma and #request gets interpolated into the list.
Is it actually equivalent to:
my $reply = $service->call('requestMessage' => \#request, $header);
What's going on here?
EDIT: Thanks for the answers. I am well aware of the difference between pass by value and pass by reference. I was asking if an apparent pass by value was being converted into a pass by reference. Apparently not. Thank you all for answering.
The code in question:
my $reply = $service->call('requestMessage' => #request, $header);
is not equivalent to this:
my $reply = $service->call('requestMessage' => \#request, $header);
It is, as you surmised, equivalent to this:
my $reply = $service->call('requestMessage', #request, $header);
Sometimes, the "fat comma," as => is known, is used to indicate a relationship between positional parameters. For example, the link between the method name some_method and its intended #arguments in this code:
$server->distribute_across_nodes(some_method => #arguments);
What happens when you put an array on the right side of a => operator?
=> is the fat comma. It has no effect on the RHS. It automatically quotes the LHS if the LHS is a bareword.
The rest of your question seems to boil down to if there is a difference between passing a function an array versus a reference to an array: Yes, there is. In the first case, the array is flattened and passed to the function. So, if the array has 1,000 elements, the functions argument list will grow by 1,000 elements.
In the second case, a reference to the array is passed, so the size of the argument list does not depend on the size of the array pointed to by the reference passed to the function.
There's a school of thought that => should be used as some kind of emphatic comma, even when it makes no difference. Advocates use it to indicate that one thing describes or acts on another, e.g.:
split /,/ => $var;
Maybe the author of your code falls into this camp?
Looking at the SOAP::Lite code, it eventually makes this call
$serializer->envelope(method => shift, #_)
So your original call
$service->call('requestMessage' => #request, $header);
is just using the fat comma to emphasize that the contents of (#request, $header ) will become the parameters for the soap call requestMessage. This is less than clear, because $header is part of the parameters, but the convention doesn't make it clear. I'd say that, in this case, the fat comma is not adding anything.
I have seen the "emphatic comma" used in CGI scripts, like so (untested)
$q->param(foo => $bar)
I think it does a pretty good job there of indicating that this call will set the parameter foo. But clearly this can also be confusing. Use with caution.
It will pass "requestMessage", then all values in #request (as the 2nd, 3rd... etc. parameters), and then $header. These will probably get forced into a hash.
Here's an example:
perl -MData::Dumper -e '#a = (1, 2, 3, 4);
%b = ('a' => #a, 'c');
print Dumper(\%b);'
$VAR1 = {
'4' => 'c',
'a' => 1,
'2' => 3
};
So in this case it's the same as
%b = ('a' => 1, 2 => 3, 4 => 'c');

Is %$var dereferencing a Perl hash?

I'm sending a subroutine a hash, and fetching it with my($arg_ref) = #_;
But what exactly is %$arg_ref? Is %$ dereferencing the hash?
$arg_ref is a scalar since it uses the $ sigil. Presumably, it holds a hash reference. So yes, %$arg_ref deferences that hash reference. Another way to write it is %{$arg_ref}. This makes the intent of the code a bit more clear, though more verbose.
To quote from perldata(1):
Scalar values are always named with '$', even when referring
to a scalar that is part of an array or a hash. The '$'
symbol works semantically like the English word "the" in
that it indicates a single value is expected.
$days # the simple scalar value "days"
$days[28] # the 29th element of array #days
$days{'Feb'} # the 'Feb' value from hash %days
$#days # the last index of array #days
So your example would be:
%$arg_ref # hash dereferenced from the value "arg_ref"
my($arg_ref) = #_; grabs the first item in the function's argument stack and places it in a local variable called $arg_ref. The caller is responsible for passing a hash reference. A more canonical way to write that is:
my $arg_ref = shift;
To create a hash reference you could start with a hash:
some_sub(\%hash);
Or you can create it with an anonymous hash reference:
some_sub({pi => 3.14, C => 4}); # Pi is a gross approximation.
Instead of dereferencing the entire hash like that, you can grab individual items with
$arg_ref->{key}
A good brief introduction to references (creating them and using them) in Perl is perldoc perfeftut. You can also read it online (or get it as a pdf). (It talks more about references in complex data structures than in terms of passing in and out of subroutines, but the syntax is the same.)
my %hash = ( fred => 'wilma',
barney => 'betty');
my $hashref = \%hash;
my $freds_wife = $hashref->{fred};
my %hash_copy = %$hash # or %{$hash} as noted above.
Soo, what's the point of the syntax flexibility? Let's try this:
my %flintstones = ( fred => { wife => 'wilma',
kids => ['pebbles'],
pets => ['dino'],
}
barney => { # etc ... }
);
Actually for deep data structures like this it's often more convenient to start with a ref:
my $flintstones = { fred => { wife => 'Wilma',
kids => ['Pebbles'],
pets => ['Dino'],
},
};
OK, so fred gets a new pet, 'Velociraptor'
push #{$flintstones->{fred}->{pets}}, 'Velociraptor';
How many pets does Fred have?
scalar # {flintstones->{fred}->{pets} }
Let's feed them ...
for my $pet ( # {flintstones->{fred}->{pets} } ) {
feed($pet)
}
and so on. The curly-bracket soup can look a bit daunting at first, but it becomes quite easy to deal with them in the end, so long as you're consistent in the way that you deal with them.
Since it's somewhat clear this construct is being used to provide a hash reference as a list of named arguments to a sub it should also be noted that this
sub foo {
my ($arg_ref) = #_;
# do something with $arg_ref->{keys}
}
may be overkill as opposed to just unpacking #_
sub bar {
my ($a, $b, $c) = #_;
return $c / ( $a * $b );
}
Depending on how complex the argument list is.