perl: printing object properties - perl

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".

Related

regarding usage of arrow notation in 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.

How to tell perl to print to a file handle instead of printing the file handle?

I'm trying to wrap my head around the way Perl handles the parsing of arguments to print.
Why does this
print $fh $stufftowrite
write to the file handle as expected, but
print($fh, $stufftowrite)
writes the file handle to STDOUT instead?
My guess is that it has something to do with the warning in the documentation of print:
Be careful not to follow the print keyword with a left parenthesis unless you want the corresponding right parenthesis to terminate the arguments to the print; put parentheses around all arguments (or interpose a + , but that doesn't look as good).
Should I just get used to the first form (which just doesn't seem right to me, coming from languages that all use parentheses around function arguments), or is there a way to tell Perl to do what I want?
So far I've tried a lot of combination of parentheses around the first, second and both parameters, without success.
On lists
The structure bareword (LIST1), LIST2 means "apply the function bareword to the arguments LIST1", while bareword +(LIST1), LIST2 can, but doesn't neccessarily mean "apply bareword to the arguments of the combined list LIST1, LIST2". This is important for grouping arguments:
my ($a, $b, $c) = (0..2);
print ($a or $b), $c; # print $b
print +($a or $b), $c; # print $b, $c
The prefix + can also be used to distinguish hashrefs from blocks, and functions from barewords, e.g. when subscripting an hash: $hash{shift} returns the shift element, while $hash{+shift} calls the function shift and returns the hash element of the value of shift.
Indirect syntax
In object oriented Perl, you normally call methods on an object with the arrow syntax:
$object->method(LIST); # call `method` on `$object` with args `LIST`.
However, it is possible, but not recommended, to use an indirect notation that puts the verb first:
method $object (LIST); # the same, but stupid.
Because classes are just instances of themselves (in a syntactic sense), you can also call methods on them. This is why
new Class (ARGS); # bad style, but pretty
is the same as
Class->new(ARGS); # good style, but ugly
However, this can sometimes confuse the parser, so indirect style is not recommended.
But it does hint on what print does:
print $fh ARGS
is the same as
$fh->print(ARGS)
Indeed, the filehandle $fh is treated as an object of the class IO::Handle.
(While this is a valid syntactic explanation, it is not quite true. The source of IO::Handle itself uses the line print $this #_;. The print function is just defined this way.)
Looks like you have a typo. You have put a comma between the file handle and the argument in the second print statement. If you do that, the file handle will be seen as an argument. This seems to apply only to lexical file handles. If done with a global file handle, it will produce the fatal error
No comma allowed after filehandle at ...
So, to be clear, if you absolutely have to have parentheses for your print, do this:
print($fh $stufftowrite)
Although personally I prefer to not use parentheses unless I have to, as they just add clutter.
Modern Perl book states in the Chapter 11 ("What to Avoid"), section "Indirect Notation Scalar Limitations":
Another danger of the syntax is that the parser expects a single scalar expression as the object. Printing to a filehandle stored in an aggregate variable seems obvious, but it is not:
# DOES NOT WORK AS WRITTEN
say $config->{output} 'Fun diagnostic message!';
Perl will attempt to call say on the $config object.
print, close, and say—all builtins which operate on filehandles—operate in an indirect fashion. This was fine when filehandles were package globals, but lexical filehandles (Filehandle References) make the indirect object syntax problems obvious. To solve this, disambiguate the subexpression which produces the intended invocant:
say {$config->{output}} 'Fun diagnostic message!';
Of course, print({$fh} $stufftowrite) is also possible.
It's how the syntax of print is defined. It's really that simple. There's kind of nothing to fix. If you put a comma between the file handle and the rest of the arguments, the expression is parsed as print LIST rather than print FILEHANDLE LIST. Yes, that looks really weird. It is really weird.
The way not to get parsed as print LIST is to supply an expression that can legally be parsed as print FILEHANDLE LIST. If what you're trying to do is get parentheses around the arguments to print to make it look more like an ordinary function call, you can say
print($fh $stufftowrite); # note the lack of comma
You can also say
(print $fh $stufftowrite);
if what you're trying to do is set off the print expression from surrounding code. The key point is that including the comma changes the parse.

perl encapsulate single variable in double quotes

In Perl, is there any reason to encapsulate a single variable in double quotes (no concatenation) ?
I often find this in the source of the program I am working on (writen 10 years ago by people that don't work here anymore):
my $sql_host = "something";
my $sql_user = "somethingelse";
# a few lines down
my $db = sub_for_sql_conection("$sql_host", "$sql_user", "$sql_pass", "$sql_db");
As far as I know there is no reason to do this. When I work in an old script I usualy remove the quotes so my editor colors them as variables not as strings.
I think they saw this somewhere and copied the style without understanding why it is so. Am I missing something ?
Thank you.
All this does is explicitly stringify the variables. In 99.9% of cases, it is a newbie error of some sort.
There are things that may happen as a side effect of this calling style:
my $foo = "1234";
sub bar { $_[0] =~ s/2/two/ }
print "Foo is $foo\n";
bar( "$foo" );
print "Foo is $foo\n";
bar( $foo );
print "Foo is $foo\n";
Here, stringification created a copy and passed that to the subroutine, circumventing Perl's pass by reference semantics. It's generally considered to be bad manners to munge calling variables, so you are probably okay.
You can also stringify an object or other value here. For example, undef stringifies to the empty string. Objects may specify arbitrary code to run when stringified. It is possible to have dual valued scalars that have distinct numerical and string values. This is a way to specify that you want the string form.
There is also one deep spooky thing that could be going on. If you are working with XS code that looks at the flags that are set on scalar arguments to a function, stringifying the scalar is a straight forward way to say to perl, "Make me a nice clean new string value" with only stringy flags and no numeric flags.
I am sure there are other odd exceptions to the 99.9% rule. These are a few. Before removing the quotes, take a second to check for weird crap like this. If you do happen upon a legit usage, please add a comment that identifies the quotes as a workable kludge, and give their reason for existence.
In this case the double quotes are unnecessary. Moreover, using them is inefficient as this causes the original strings to be copied.
However, sometimes you may want to use this style to "stringify" an object. For example, URI ojects support stringification:
my $uri = URI->new("http://www.perl.com");
my $str = "$uri";
I don't know why, but it's a pattern commonly used by newcomers to Perl. It's usually a waste (as it is in the snippet you posted), but I can think of two uses.
It has the effect of creating a new string with the same value as the original, and that could be useful in very rare circumstances.
In the following example, an explicit copy is done to protect $x from modification by the sub because the sub modifies its argument.
$ perl -E'
sub f { $_[0] =~ tr/a/A/; say $_[0]; }
my $x = "abc";
f($x);
say $x;
'
Abc
Abc
$ perl -E'
sub f { $_[0] =~ tr/a/A/; say $_[0]; }
my $x = "abc";
f("$x");
say $x;
'
Abc
abc
By virtue of creating a copy of the string, it stringifies objects. This could be useful when dealing with code that alters its behaviour based on whether its argument is a reference or not.
In the following example, explicit stringification is done because require handles references in #INC differently than strings.
$ perl -MPath::Class=file -E'
BEGIN { $lib = file($0)->dir; }
use lib $lib;
use DBI;
say "ok";
'
Can't locate object method "INC" via package "Path::Class::Dir" at -e line 4.
BEGIN failed--compilation aborted at -e line 4.
$ perl -MPath::Class=file -E'
BEGIN { $lib = file($0)->dir; }
use lib "$lib";
use DBI;
say "ok";
'
ok
In your case quotes are completely useless. We can even says that it is wrong because this is not idiomatic, as others wrote.
However quoting a variable may sometime be necessary: this explicitely triggers stringification of the value of the variable. Stringification may give a different result for some values if thoses values are dual vars or if they are blessed values with overloaded stringification.
Here is an example with dual vars:
use 5.010;
use strict;
use Scalar::Util 'dualvar';
my $x = dualvar 1, "2";
say 0+$x;
say 0+"$x";
Output:
1
2
My theory has always been that it's people coming over from other languages with bad habits. It's not that they're thinking "I will use double quotes all the time", but that they're just not thinking!
I'll be honest and say that I used to fall into this trap because I came to Perl from Java, so the muscle memory was there, and just kept firing.
PerlCritic finally got me out of the habit!
It definitely makes your code more efficient, but if you're not thinking about whether or not you want your strings interpolated, you are very likely to make silly mistakes, so I'd go further and say that it's dangerous.

Why does this subroutine work if I type out its arguments literally, but not if I give the arguments in the form of a variable?

I am using a perl package (Biomart), that includes a subroutine called addFilter(). That subroutine needs a couple of arguments, including one that needs to be of the format "nr:nr:nr"
If I use the subroutine as follows, it works fine:
$query->addFilter("chromosomal_region", ["1:1108138:1108138","1:1110294:1110294"]);
However, if I use it like this, it does not work:
my $string = '"1:1108138:1108138","1:1110294:1110294","1:1125105:1125105"';
$query->addFilter("chromosomal_region", ['$string']);
Since there are tens of thousands of those arguments that I construct in a for loop, I really need the second way to work... What could be causing this? I hope someone can help me out, many thanks in advance!
Because you seem to be trying to write in a language that's not Perl. '"this","that","another"' isn't an array, it's a string. And '$string' doesn't interpolate or include $string in any way because it uses single quotes. It just produces a string that starts with a dollar sign and ends with "string".
Something more like what you intend would be:
my #things = ("1:1108138:1108138","1:1110294:1110294","1:1125105:1125105");
$query->addFilter("chromosomal_region", \#things);
-or-
$query->addFilter("chromosomal_region", [ #things ] );
And to build it up dynamically, you can simply do push #things, $value in a loop or whatever you need.
'$string' is literally "$string"; the variable isn't replaced with its contents. Lose the single quotes.
Of course, it's unlikely passing a reference to an array consisting of a single comma-separated string with quotes embedded in it is going to do the same thing as passing a reference to an array of strings.
Try something like:
my $ref = ["1:1108138:1108138","1:1110294:1110294"];
$query->addFilter("chromosomal_region", $ref);
I agree with hobbs...if you want to take many inputs like that, you can use a for loop and an array like this (provided you are taking inputs from STDIN):
for ($line = <STDIN> && $line ne "end\n")
{
chomp($line);
push #values,$line;
}
It takes data and puts in values array. You have to indicate the end of data by "end".
And for your error, what others said was right. Perl's variable interpolation works only for variables in double quotes.

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.