DEV Community

Nicholas Hubbard
Nicholas Hubbard

Posted on

4 Unrelated Perl Tidbits

I recently acquired a copy of Programming Perl, often referred to as "The Camel Book" in the Perl community. After reading the first 4 chapters I thought I would share a few Perl tidbits I found interesting.

While <> is True

Say we have the following file named logos.txt.

Onion
Camel

Raptor
Enter fullscreen mode Exit fullscreen mode

And in the same directory we have the following program named scratch.pl.

open my $fh, '<', 'logos.txt' or die;
while (my $logo = <$fh>) {
    print $logo;
}
close $fh;
Enter fullscreen mode Exit fullscreen mode

As expected our program prints the contents of logos.txt.

$ perl ./scratch.pl
Onion
Camel

Raptor
Enter fullscreen mode Exit fullscreen mode

Something I never really considered though, is why doesn't the loop exit when <> reads the empty line in logos.txt? Shouldn't <> return an empty string which is a false value?

According to Programming Perl, the reason why the loop doesn't exit is because <> reads the newline at the end of the line so we actually get "\n" which is a true value. Turns out this is a fib, and the actual reason is that while (my $logo = <$fh>) ... expands into while (defined (my $logo = <$fh>)) ..., and "\n" is a defined value.

We can show this by deparsing the code with B::Deparse.

$ perl -MO=Deparse,-p,-sCi2 -ne 42
LINE: while (defined(($_ = readline(ARGV)))) {
  '???';
}
-e syntax OK
Enter fullscreen mode Exit fullscreen mode

Heredocs Can Execute Shell Commands

Most Perl programmers know that if you single quote a heredocs terminating string you prevent variable interpolation.

my $var = 12;
print <<'EOS';
Hello
$var = 12
EOS
Enter fullscreen mode Exit fullscreen mode

You can see in the programs output that $var was not interpolated.

$ perl ./scratch.pl
Hello
$var = 12
Enter fullscreen mode Exit fullscreen mode

But did you know that if you backquote the terminating string then each line is executed as a shell command?

print <<`EOC`;
echo this is a shell command
echo this is also a shell command
EOC
Enter fullscreen mode Exit fullscreen mode

When we run this program we can see that the echo commands were executed.

$ perl ./scratch.pl
this is a shell command
this is also a shell command
Enter fullscreen mode Exit fullscreen mode

The Comma Operator

I always took commas for granted, never realizing they were actually an operator.

Did you ever wonder why lists return their last element when evaluated in scalar context? Turns out it is due to the comma operator.

In scalar context the comma operator "," ignores its first argument, and returns its second element evaluated in scalar context.

This means that in scalar context the list (11, 22, 33) will evaluate to 33. The first comma operator will throw away the 11 and then return (22, 33) evaluated in scalar context, which will be evaluated by throwing away the 22 and returning 33.

Auto-Incrementing Strings

In perl you can not only auto-increment numbers, but also strings. To increment a string it must match the regex /^[a-zA-Z]*[0-9]*\z/.

Single alphabet character strings are incremented intuitively.

$ perl -E 'my $v = "a"; say ++$v'
b
$ perl -E 'my $v = "B"; say ++$v'
C
Enter fullscreen mode Exit fullscreen mode

What happens though if we increment a non-alphanumeric char. Will it give the next ASCII character? Turns out non-alphanumeric characters are treated as 0's when incrementing. Fortunately if we use warnings Perl will give us a heads up.

$ perl -W -E 'my $v = "-"; say ++$v'
Argument "-" treated as 0 in increment (++) at -e line 1.
1
Enter fullscreen mode Exit fullscreen mode

What happens if we increment z, which is at the end of the alphabet? Do we wrap back around to a? This is where things get interesting. Perl increments the string just like you would in a regular number system. Just like 9 + 1 = 10 in decimal z + 1 = aa in … stringimal.

$ perl -E 'my $v = "z"; say ++$v'
aa
Enter fullscreen mode Exit fullscreen mode

Here are some more examples to show you the magic of string auto-incrementing.

$ perl -W -E 'my $v1 = "foo"; say ++$v1'
fop
$ perl -W -E 'my $v1 = "az"; say ++$v1'
ba
$ perl -W -E 'my $v1 = "a9"; say ++$v1'
b0
Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
matthewpersico profile image
Matthew O. Persico

I did not realize that the comma operator’s operation was what makes lists return their last element in scalar context. I’ve been Perling since 1996. 🤦🏻‍♂️ Thank you for that.

Collapse
 
nicholasbhubbard profile image
Nicholas Hubbard

That one surprised me as well!

Collapse
 
thibaultduponchelle profile image
Tib

I like this kind of blog post :) thank you