Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

What I Most Recently Learned in Perl, But Should Have Already Known

by liverpole (Monsignor)
on Aug 16, 2006 at 22:43 UTC ( #567774=perlmeditation: print w/replies, xml ) Need Help??

When I began learning Perl, almost exactly 6 years ago, it was so much fun that I couldn't get enough of learning new things.  I had bought Learning Perl, vol. 2, a couple of years earlier, but hadn't made much of a dent in it, mostly because I wasn't involved in actually using it for any programming.  So just reading about it was doomed to failure, in retrospect.

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 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 hex and oct, but there isn't a bin equivalent, and though 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 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 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?"


Replies are listed 'Best First'.
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by jplindstrom (Monsignor) on Aug 17, 2006 at 08:34 UTC
    One thing that bit me a few months ago: sort in scalar context is undefined.

    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.


Re: What I Most Recently Learned in Perl, But Should Have Already Known
by Velaki (Chaplain) on Aug 17, 2006 at 10:57 UTC

    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.


    "Perl. There is no substitute."
      I cannot agree with this more. I learned most of the Perl I know today through Perl Golfing (both participating and decoding other answers).

      Ted Young

      ($$<<$$=>$$<=>$$<=$$>>$$) always returns 1. :-)
      I am afraid to look into the aby... at obfuscated/golf code, since I am afraid it might look ba... be contagious.

      (-: 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.)

Re: What I Most Recently Learned in Perl, But Should Have Already Known
by wfsp (Abbot) on Aug 17, 2006 at 11:03 UTC
    Using a foreach loop on an AoH creates an alias of the hash which goes out of scope after the loop.

    #!/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 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
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by GrandFather (Sage) on Aug 16, 2006 at 22:55 UTC

    You may want to look at pack and unpack too.

    DWIM is Perl's answer to Gödel
      Yes, GrandFather, I know about pack and unpack.  And although I don't consider myself an expert at them (... yet :-D), I have used them in quite a few programs to date.  Anyone who has done socket programming (for example) will certainly have learned how to use them.

      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 Updated QuickTime format movie file dumper. 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;

        DWIM is Perl's answer to Gödel
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by imp (Priest) on Aug 21, 2006 at 02:37 UTC
    I recently learned how to find out what Perl thinks I mean by my code. The magic of B::Deparse. This answered some mysteries, for example why this code will not stop on values that are seen as false:
    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($_ = <ARGV>)) { (); }
    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' };
    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.

      Hi imp,

      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.

      i have those in my ~/.aliases
      # Perl
      alias p='perl -nle'                    #> process file by line, chomp
      alias pp='perl -ple'                   #> process file by line, chomp and print
      alias pdbg='perl -de 1'                #> perl debugger
      alias dpl='perl -MO=Deparse'           #> show how perl see this code
      alias dpl2='perl -MO=Deparse,-l,-p,-q,-sCT' #> show how perl see this code, with line no, parens and more
      alias cpan='perl -MCPAN -e shell'      #> Start CPAN
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by imp (Priest) on Aug 18, 2006 at 00:14 UTC
    That you can get an array of hashes from DBI like this:
    my $aoh = $dbh->selectall_arrayref($sql,{Slice => {}});
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by gawatkins (Monsignor) on Aug 17, 2006 at 16:29 UTC

    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,
    Greg W

      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.

      Igor 'izut' Sutton
      your code, your rules.

        I always run into the problem of the default case when I use that -- what if $function isn't a key in %functions? The error message "Undefined subroutine &main:: called" can be very difficult to figure out.

        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.
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by imp (Priest) on Aug 22, 2006 at 21:17 UTC
    I was aware of this:
    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;
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by uksza (Abbot) on Aug 18, 2006 at 22:57 UTC
    well, few days ago I 'discovered' ||= operator ;)

    greetz, Uksza

    Yes, smart people know that fat arrow autoquotes the left argument. But why should you require your code to be maintained by smart people?
    Randal L. Schwartz, Perl hacker
Re: What I Most Recently Learned in Perl, But Should Have Already Known
by arpie (Initiate) on Aug 22, 2006 at 18:08 UTC
    Map and grep. Especially for set functions, e.g. (untested code, but that should give the idea)
    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.

Re: What I Most Recently Learned in Perl, But Should Have Already Known
by graff (Chancellor) on Mar 18, 2007 at 00:05 UTC
    Cool thread. My latest revelation was about Exporter. I've written some modules that don't need it at all, and I've written some that do need it, in order for a caller script to just use a given function. But it wasn't till a few days ago that I finally learned (or figured out / absorbed / understood) what the difference is between needing Exporter vs. not needing it:

    The ones that didn't need Exporter were OO-style; the "ModuleName->new()" or "new ModuleName" method never needs to be explicitly exported, and the returned object reference provides the caller with simple and direct access to the module's methods.

    The modules that aren't OO-style don't supply that sort of handy object reference, so Exporter is needed in order for the module's function names to be accessible to the caller without the clunky "ModuleName::" prefix.

    At least, that's how I've come to understand it (finally). I must have known some part of this before (when writing those OO-style modules), but it turns out I don't write modules all that often, and I actually did scratch my head a bit recently when writing a simple "functions-only" module, trying to recall what incantation to use involving Exporter, and seeing that some of my older modules didn't use it at all (yet these never needed the "ModuleName::" syntax when being used).

    I attribute my surprise to my habitually "procedural" mindset, which Perl supports so effectively.

Re: What I Most Recently Learned in Perl, But Should Have Already Known
by Ray Smith (Beadle) on Aug 21, 2006 at 02:09 UTC
    Nice insight into your Perl experience!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://567774]
Approved by GrandFather
Front-paged by apotheon
[Discipulus]: tozzetti & vinsanto
[Lady_Aleena]: The whole line is push @line, ref($list_addition ) ? @$list_addition : $list_addition if $list_addition;
[Lady_Aleena]: And I forgot to do the array check, I'm such a doofus today.
[Lady_Aleena]: push @line, ref($list_addition ) eq 'ARRAY' ? @$list_addition : $list_addition if $list_addition; #trying again
[shmem]: Discipulus: yummy. I like those. Didn't have them for some time now, forgot the name. Should go get some...
[shmem]: Lasy_Aleena: correct, although for clarity I'd use an if() block, not a statement modifier
[shmem]: this allows you to add an else if maintainance makes it neccesary
[Lady_Aleena]: shmem, okeydokey.
[shmem]: ...or logging or debugging or such

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (8)
As of 2017-04-27 11:51 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (504 votes). Check out past polls.