But in the summer of 2000, I was using it for work, and loving the process. The book "Learning Perl" (and several other newly-acquired Perl books as well) now became not only useful, but a source of new learning and fresh inspiration each time they were opened. It even became a habit to read chapters from Perl books in my spare time, just to learn all the cool constructs I had never encountered in any other languages. I still remember the excitement I felt discovering for the first time about tied variables. Or grasping the beauty of data structures which behaved one way in scalar context, and another way in list context, and the sheer beauty and logic of such a system. Or the intricate wealth of reusability that came from writing object-oriented modules.
And of course, the plethora of functions! Every time I researched this still-new (to me) language, there were all the functions that I loved in C, and new ones everywhere I looked. Add to that the complex user-defined data structures, sophisticated regular expressions, elaborate subroutine closures ... "Swiss-army Chainsaw" didn't even begin to describe the power!
But I have to admit I don't spend the same long hours reading about Perl the way I used to. I'm sure it's a common phenomenon for many; you look up what you need, when you need it, and that's about all. I did recently purchase Mark Jason Dominus' book, "Higher Order Perl", and although it's a fascinating and thoroughly illustrative book, I confess that I only read maybe 10-20 minutes of it at a time, not the 2-3 hours that I used to spend entrenching myself in learning. One gets to a point, perhaps, where it one feels that they know essentially all of the basics; no more big surprises when it comes to the fundamentals.
So it was today that I surprisingly came across something simple that I realized I didn't know how to do. While writing a program to demonstrate the application of the [wikipedia://Bailey-Borwein-Plouffe formula], I couldn't figure out how to to convert a very long string, containing a binary value, into a hexadecimal value. I knew about [doc://hex] and [doc://oct], but there isn't a bin equivalent, and though [doc://sprintf] will output in binary, there wasn't an obvious way to make Perl treat my string as binary on input.
When I came across the answer, I realized I had missed something basic, back when I was just starting out with Perl. The [doc://oct] function can work with a variety of input bases (not just octal), by specifying the base at the front:
0xN .... interpret N as hexadecimal
0bN .... interpret N as binary
N .... interpret N as octal
And the [doc://oct|oct documentation] even suggests a method of handling any of the common 4 bases, with:
The following will handle decimal, binary, octal, and hex
in the standard Perl or C notation:
$val = oct($val) if $val =~ /^0/;
So now I'm wondering what other basics I may have missed along the way, either because I never noticed them the first time through, or just didn't need to know them until now.
And I'm curious, and ask the question of you, my brethren: "What basic function, construct, or concept in Perl did you recently learn, that you were surprised to find you hadn't already known?"
You may want to look at pack and unpack too.
But how about you? Do you have any stories to share about concepts which you've learned in the recent past?
I learned something about pack/unpack writing [id://534371]. But the cool thing I learned writing that code was using can to assist in the context of a "dispatch by name":
my $member = "dump_$key";
my $name = "name_$key";
$name = $self->can($name) ? $self->$name () . ' ' : '';
...
if ($self->can($member)) {
$self->$member ($pos, $len);
$key is an "atom" code from the file being parsed. If there is a handler for the atom $self->$member dispatches to the code to handle it. One neat thing about this is that a derived class can add handlers and the parser just takes it all in its stride. I reckon that's pretty cool - perhaps even elegant. :)
One way to do a binary conversion is:
my $str = '001100010011001100110001';
my $value = pack ('B*', $str);
print $value;
That isn't a big deal until you do this in a sub:
return( sort @some_array );
that is supposed to return a sorted list. And then you wonder how many elements the list contains:
my $count = get_the_sorted_list(); #Scalar context propagates to sort
That's pretty annoying when you happen to do it, and pretty important to know about so you don't. I sure was surprised the first time I encountered it.
/J
I've discovered that an excellent way to dust off those less-than-oft remembered features of Perl is to try to interpret the obfuscated JAPH programs. You wind up looking up deprecated and seldom-used operators and functions in the course of trying to decipher what those things do.
The advantage to this is that it sometimes gets your creative juices flowing in a new way, and suddenly study might be your newest old toy.
Musing,
-v.
Ted Young
($$<<$$=>$$<=>$$<=$$>>$$) always returns 1. :-)(-: Are you saying that I should relax -- it helps keyboard speed if my fingers transform into tentacles and Cthulhu worshippers can scuba dive cheaper because of breathing under water? :-)
I recently learned how neat parsing parameters is with Getopt::Long.
What I've learnt the last year or so is to write tests for all code I write. The main advantages are development speed (for larger code), that you organize your code differently so it is testable and it really helps when you rewrite code.
For my hobby project, I'm going to make an alternative implementation of a feature (big data volumes will be stored in a sql database). I can copy the tests and keep the interface! Neat.
Since that was borderline elegant, I'll also show a monk's humility by mentioning a horrible kludge I'll add to that. Objects will rebless themselves to the other implementation type when the data size gets larger/smaller! (A nicer implementation would be to have an implementation of the storage which are contained in another object -- and let that create/delete objects with data. That gets complicated for other reasons.)
#!/usr/bin/perl
use strict;
use warnings;
my $recs = [
# short records for brevity
{id => 1},
{id => 2},
{id => 3},
];
my $rec;
for $rec (@{$recs}){
# $rec is an alias...
if ($rec->{id} == 1){
last;
}
}
# ... which is now out of scope :-(
print "$rec->{id}\n"; # Use of uninitialized value...
# what I should have done
($rec) = grep {$_->{id} == 1} @{$recs};
print "$rec->{id}\n"; # 1
# $rec is an alias...
It's the previously declared lexical, implicitly localized. See [http://perldoc.perl.org/perlsyn.html#Foreach-Loops-for-foreach|perldoc perlsyn]...
Shorter example, without the need to blame AoH for the problem:
my $var = 4;
for $var (1 .. 9) {
last if $var == 7;
}
print $var; # prints: 4
unless, once I learned it, I quit having to create complex if-else statements to decide if something did not happen. All languages should have an equivalent to unless
Thank you,Continuing the if-else statements problem, the idiom I like most is:
my $function = 'a';
my %functions = (
'a' => sub { ... },
'b' => sub { ... },
);
$functions{$function}->();
It's amazing how this replace an entire switch or if-else statements.
And the straightforward fix isn't all that pretty:
($functions{$function} || $functions{default})->();
But I admit that I still use it. With comments, if there is any chance that someone with a capacity to do me bodily harm might read the code.
I think this way is prettier.
sub do_something {
my ($function) = @_;
$function = 'default' unless exists $functions{$function};
$functions{$function}->();
}
my $aoh = $dbh->selectall_arrayref($sql,{Slice => {}});
while (<>) {
}
When writing that loop explicitly I would be testing it like this:
while (defined( my $line = <>)) {
}
It turns out that is exactly what perl is doing as well, as seen below:
perl -MO=Deparse -e 'while (<>) {}'
while (defined($_ = )) {
();
}
It's also interesting to see what the parser thinks about other code, such as:
perl -MO=Deparse -e ' if(1) {print "true"}'
do {
print 'true'
};
And
perl -MO=Deparse -e ' print "true" if 1' print 'true';And it is useful for seeing what some of the code from the Obfuscation section is actually doing.
perl -MO=Deparse -e ' print "true" if 1'
If we do if 0 something even funnier happens:
$ /usr/bin/perl -MO=Deparse -e 'print "true" if 0' '???';
But which is most amusing is the fact that the deparsed code generates a warning:
$ /usr/bin/perl -w -e 'print "true" if 0' $ /usr/bin/perl -w -e '"???"' Useless use of a constant in void context at -e line 1.
--
David Serrano
'???' actually is no real thing. It's more like Deparse saying, this should be optimized away.
E. g. every "Useless use of a constant in void context" also results in this.
I myself didn't know about B::Deparse until about a half a year ago, and only then as a result of being pointed to it by the other monks.
If you haven't seen it yet, check out this obfuscation, which I wrote to take advantage of some of the properties of B::Deparse.
my @a=(1,2,3,4,5);
my @b=(4,5,6,7,8);
my %a = map { $_ => 1 } @a;
my %b = map { $_ => 1 } @b;
my @intersection = grep { exists $a{$_} } @b;
my @intersection_complement = grep { !exists $a{$_} } @b;
That reminds me that some time back I tried to get a grip on hash slices.
In similar use to your example:
my @intersection = grep {defined} @{{map {$_=>$_} @a}}{@b}Though in everyday life I prefer your method, since I tend to get headache from thinking about that slices and also definitely got the syntax and/or semantics wrong the first time always.
my $indent = ' 'x5; # Yields ' 'But didn't realize I could also do this:
my @list = (1)x5; # Yields (1,1,1,1,1)So I can stop doing this:
@placeholders = map {'?'} @columns;
And start doing this:
@placeholders = ('?')x @columns;
perlmonks.org content © perlmonks.org and arpie, BerntB, gawatkins, GrandFather, Hue-Bond, imp, izut, jplindstrom, liverpole, pKai, Ray Smith, sfink, TedYoung, uksza, Velaki, wfsp
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03