regarding usage of arrow notation in perl - perl

I've following two statements written in perl :
#m1 = ( [1,2,3],[4,5,6],[7,8,9] ); # It is an array of references.
$mr = [ [1,2,3],[4,5,6],[7,8,9] ]; # It is an anonymous array. $mr holds reference.
When I try to print:
print "$m1[0][1]\n"; # this statement outputs: 2; that is expected.
print "$mr->[0][1]\n"; #this statement outputs: 2; that is expected.
print "$mr[0][1]\n"; #this statement doesn't output anything.
I feel second and third print statements are same. However, I didn't any output with third print statement.
Can anyone let me know what is wrong with third print statement?

This is simple. $mr is a reference. So you use the Arrow Operator to dereference.
Also, if you would use use warnings; use strict;, you would have received a somewhat obvious error message:
Global symbol "#mr" requires explicit package name

$mr is a scalar variable whose value is a reference to a list. It is not a list, and it can't be used as if it was a list. The arrow is needed to access the list it refers to.
But hold on, $m1[0] is also not a list, but a reference to one. You may be wondering why you don't have to write an arrow between the indexes, like $m1[0]->[1]. There's a special rule that says you can omit the arrow when accessing list or hash elements in a list or hash of references, so you can write $mr->[0][1] instead of $mr->[0]->[1] and $m1[0][1] instead of $m1[0]->[1].

$mr holds a reference (conceptually similar to the address of a variable in compiled languages). thus you have an extra level of indirection. replace $mrwith $$mr and you'll be fine.
btw, you can easily check questions like these by browsing for tutorials on perldoc.

You said:
print "$m1[0][1]\n"; # this statement outputs: 2; that is expected.
print "$mr[0][1]\n"; #this statement doesn't output anything.
Notice how you used the same syntax both times.
As you've established by this first line, this syntax accesses the array named: #m1 and #mr. You have no variable named #mr, so you get undef for $mr[0][1].
Maybe you don't realizes that scalar $mr and array #mr have no relation to each other.
Please use use strict; use warnings; to avoid these and many other errors.

Related

Perl - Global symbol requires explicit package name

I am calling a perl subroutine
&ProcessInput($line, \%txcountershash, \%txhash);
I have this definition:
sub ProcessInput() {
my $word;
my $counterkey;
my $line = $_[0];
my $countershash = $_[1];
my $outputhash = $_[2];
# remove all the blanks from the line
$line =~ s/\s+//g;
my ($port,$counter,$value,$datetime) = split('\|',$line,4);
my $counterdesc = $countershash{$counter};
the line that causes the problem is the last line. It says that global symbol %countershash requires explicit package name. I'm not sure why it's giving me the error. There aren't any problems otherwise, if I comment that line out the script runs. The hash is set up as an error code for a key and a description that is the value. I'm trying to get the value at a particular key in $countershash so I can add the error description to the output hash.
The problem is dereferencing. you should dereference the hash inside the subroutine
my $counterdesc = $countershash->{$counter};
-> this is called arrow operator which is used to deference the array and hashes.
The code $counterhash{$counter} means "look up the key $counter in the hash %counterhash". You don't have a hash called %counterhash, you have a hash reference in a scalar variable called $counterhash. %counterhash and $counterhash are two completely different variables.
In order to look up an element in a hash reference, you need to use different syntax.
my $counterdesc = $countershash->{$counter};
Please don't use the $$countershash{$counter} syntax (previously) used in another answer. That will only confuse whoever needs to maintain your code in six months time (which might well be you).

variable "requires explicit package" name issue

my %order;
while ( my $rec = $data->fetchrow_hashref ) {
push #{ $result{ $rec->{"ID"} } }, $rec->{"item"};
push #order, $rec->{ID};
}
I get Global symbol "#order" requires explicit package name at linepush #order, $rec->{ID};
Perl's sigils identify distinct data types. And two identical identifiers are different variables entirely if they have different sigils.
my $var; # This is a scalar.
my #var; # This is an array.
my %var; # This is a hash.
Each of those three are completely different variables.
The error message you are getting is because in line one of the code you posted you declare a hash named %order, while on line four of the code you posted, you push to an array named #order. That array has never been declared. Without an explicit declaration indicating otherwise, Perl will assume the first time it sees a variable that it's intended to be a package global. And because you're using strict 'vars', or strict (where vars is implicit`), Perl doesn't let you autovivify a package global, or any other type of variable, without first declaring it unless you fully qualify its name.
This behavior is explained in perldoc strict, where it states:
This generates a compile-time error if you access a variable that was
neither explicitly declared (using any of my, our, state, or use vars
) nor fully qualified.
Since the clear intent in your code is to push values onto an array, it's probable that the simplest fix is to change your first line from my %order; to my #order;, so that you're declaring an array rather than a hash.
It's unclear, without seeing more code, to know what to do with the line where you're pushing onto an array by reference, though. Presumably you already know that part of the code to be correct.
You declare the hash %order, but try to use the array #order.

perl: printing object properties

I'm playing a bit with the Net::Amazon::EC2 libraries, and can't find out a simple way to print object properties:
This works:
my $snaps = $ec2->describe_snapshots();
foreach my $snap ( #$snaps ) {
print $snap->snapshot_id . " " . $snap->volume_id . "\n";
}
But if I try:
print "$snap->snapshot_id $snap->volume_id \n";
I get
Net::Amazon::EC2::Snapshot=HASH(0x4c1be90)->snapshot_id
Is there a simple way to print the value of the property inside a print?
$snap->volume_id is not a property, it is a method call. While you could interpolate a method call inside a string, it is exceedingly ugly.
To get all the properties of an object you can use the module Data::Dumper, included with core perl:
use Data::Dumper;
print Dumper($object);
Not in the way you want to do it. In fact, what you're doing with $snap->snapshot_id is calling a method (as in sub). Perl cannot do that inside a double-quoted string. It will interpolate your variable $snap. That becomes something like HASH(0x1234567) because that is what it is: a blessed reference of a hash.
The interpolation only works with scalars (and arrays, but I'll omit that). You can go:
print "$foo $bar"; # scalar
print "$hash->{key}"; # scalar inside a hashref
print "$hash->{key}->{moreKeys}->[0]"; # scalar in an array ref in a hashref...
There is one way to do it, though: You can reference and dereference it inside the quoted string, like I do here:
use DateTime;
my $dt = DateTime->now();
print "${\$dt->epoch }"; # both these
print "#{[$dt->epoch]}"; # examples work
But that looks rather ugly, so I would not recommend it. Use your first approach instead!
If you're still interested in how it works, you might also want to look at these Perl FAQs:
What's wrong with always quoting "$vars"?
How do I expand function calls in a string?
From perlref:
Here's a trick for interpolating a subroutine call into a string:
print "My sub returned #{[mysub(1,2,3)]} that time.\n";
The way it works is that when the #{...} is seen in the double-quoted
string, it's evaluated as a block. The block creates a reference to an
anonymous array containing the results of the call to mysub(1,2,3) .
So the whole block returns a reference to an array, which is then
dereferenced by #{...} and stuck into the double-quoted string. This
chicanery is also useful for arbitrary expressions:
print "That yields #{[$n + 5]} widgets\n";
Similarly, an expression that returns a reference to a scalar can be
dereferenced via ${...} . Thus, the above expression may be written
as:
print "That yields ${\($n + 5)} widgets\n";
Stick with the first sample you showed. It looks cleaner and is easier to read.
I'm answering this because it took me a long time to find this and I feel like other people may benefit as well.
For nicer printing of objects use Data::Printer and p():
use DateTime;
use Data::Printer;
my $dt = DateTime->from_epoch( epoch => time );
p($dt);
The PERL translator has limited depth perception within quotes. Removing them should solve the problem. Or just load the real values into a simple variable that you can print within the quotes. Might need to do that if you have objects which contain pointers to other objects:
SwissArmyChainSaw =/= PureMagic:
print("xxx".$this->{whatever}."rest of string\n");
The problem is that $snap is being interpolated inside the string, but $snap is a reference. As perldoc perlref tells us: "Using a reference as a string produces both its referent's type, including any package blessing as described in perlobj, as well as the numeric address expressed in hex."
In other words, within a string, you can't dereference $snap. Your first try was the correct way to do it.
I agree with most comment, stick to concatenation for easy reading. You can use
say
instead of print to spare of using the "\n".

Error using intermediate variable to access Spreadsheet::Read sheets

I'm no expert at Perl, wondering why the first way of obtaining numSheets is okay, while the following way isn't:
use Spreadsheet::Read;
my $spreadsheet = ReadData("blah.xls");
my $n1 = $spreadsheet->[1]{sheets}; # okay
my %sh = %spreadsheet->[1]; # bad
my $n2 = $sh{label};
The next to last line gives the error
Global symbol "%spreadsheet" requires explicit package name at newexcel_display.pl line xxx
I'm pretty sure I have the right sigils; if I experiment I can only get different errors. I know spreadsheet is a reference to an array not directly an array. I don't know about the hash for the metadata or individual sheets, but experimenting with different assumptions leads nowhere (at least with my modest perl skill.)
My reference on Spreadsheet::Read workings is http://search.cpan.org/perldoc?Spreadsheet::Read If there are good examples somewhere online that show how to properly use Spreadsheet, I'd like to know where they are.
It's not okay because it's not valid Perl syntax. The why is because that's not how Larry defined his language.
The sigils in front of variables tell you what you are trying to do, not what sort of variable it is. A $ means single item, as in $scalar but also single element accesses to aggregates such as $array[0] and $hash{$key}. Don't use the sigils to coerce types. Perl 5 doesn't do that.
In your case, $spreadsheet is an array reference. The %spreadsheet variable, which is a named hash, is a completely separate variable unrelated to all other variables with the same identifier. $foo, #foo, and %foo come from different namespaces. Since you haven't declared a %spreadsheet, strict throws the error that you see.
It looks like you want to get a hash reference from $spreadsheet->[1]. All references are scalars, so you want to assign to a scalar:
my $hash_ref = $spreadsheet->[1];
Once you have the hash reference in the scalar, you dereference it to get its values:
my $n2 = $hash_ref->{sheets};
This is the stuff we cover in the first part of Intermediate Perl.

Why do I see HASH(0xABCDEF) in my Perl output?

I am running perl, v5.6.1 built for sun4-solaris-64int
I am calling print on an array:
print "#vals\n";
and the output looks like:
HASH(0x229a4) uid cn attuid
or another example:
#foo = {};
push(#foo, "c");
print "#foo I am done now\n";
with output of:
HASH(0x2ece0) c I am done now
Where is HASH(0x2ece0) coming from?
Your braces in #foo = {} are creating it. The braces create an unnamed hash reference.
If you want to set #foo to an empty list, use #foo = ()
The key to understanding this sort of problem is that you get an extra item in the output. It's not too important what that item is.
In general, the first thing you'd want to do when your container variable has more (or less) in it than you expect is to look at it's contents. The Data::Dumper module comes with Perl and can pretty print data structures for you:
use Data::Dumper;
print Dumper( \#foo );
Once you see what is in your container, you can start to work backward to find out how it got in there. You'd eventually end up noticing that right after you initialized #foo that it already had one element, which isn't what you wanted.
Another trick is to check the number of elements in the list:
print "There are " . #array . " elements in \#array\n";
If you get a number you don't expect, work backward to find out when the extra element showed up.
You accidentally have a hash reference in #foo. When you print a reference out without dereferencing it (almost always by accident), you get a debugging string (the type of reference it is and a memory location).
I think you want my #foo = (); push #foo, "c"; rather than what you have now. On the other hand, you can also simply say my #foo; to create the array. You don't need to explicitly mark it as empty with ().
See perldoc perlreftut and perldoc perlref for more on references.
Your code should be written like this:
use strict;
use warnings;
my #foo;
push #foo, "c";
print "#foo I am done now\n";
You don't need to initialize variables in Perl, if you want to have an empty variable. You should however use my to declare a local variable. And you don't need parentheses around built-in functions, that just adds clutter.