New to “Error Handling”

The “Error Handling” chapter is really two chapters: one on dealing with error and warning messages that Perl gives you, and creating those messages on your own for people using your code.

When I first wrote this chapter, Perl’s “exception” handling was poor. We had the basics that we still use, but we hadn’t figured out all of the special cases. Try::Tiny and TryCatch didn’t show up until 2009, about four years later. Not only did I need to cover those important developments, but the background behind them.

autodie also replaced Fatal in core.

In the first edition, I covered Carp in the “Debugging” chapter. I don’t know what I was thinking then, but I’ve moved that to this chapter, leaving a big hole in that chapter; I’ll have to figure out what to do about that, but later.

I also added my ReturnValue discussion. We treat errors and return values as different things; even worse,, we treat them as unstructured data so we need to know special things about every function to know what it’s return value means. Is undef a valid result or an error? What about 0 or the empty string? With a return value object, we can ask directly. I don’t expect anyone to use my module, but the idea of this module.

I think I also avoided the easy trap for a chapter like this: I didn’t make it just a survey of modules. We know from Perl history that best practices and favorite modules have short lifetimes compared to book publishing rates. I hope I gave people enough to think about so they could evaluate future.

You can read this chapter in O’Reilly Atlas.

New to “The Magic of Tied Variables”

The tie mechanism isn’t something people reach for often, but that’s one of the reasons I included a chapter about it in Mastering Perl. No one else is writing about it either, and in some cases it an be quite useful.

I wrote several modules as examples for this chapter, but I never uploaded them to CPAN. Now I’m putting them on CPAN so they are easy to get if you want to play with them yourself. Not only that, I didn’t like the style that I used back then, so I made some cosmetic changes and light refactorings. They include:

You can read this chapter in O’Reilly Atlas.

New to “Modules as Programs”

I keep wanting to name this chapter “Modulinos”, but that doesn’t mean much to someone who doesn’t have that idea yet, so I leave it as is.

For awhile, I’ve wanted to reduce the modulino idea to a single statement, perhaps a use statement:

use Modulino;

I think I’ve got most of the way there with Modulino::Base, which I’ve included in my update to the chapter. It was an interesting journey though. I didn’t want to inherit from it because it’s not really that sort of relationship. I could add it as a role or trait, but I didn’t want to deal with complication surrounding that. I settled on a require because the code needs to run after the compile phase when all of the methods are already compiled. That was true of the code that was already controlling that behavior:

__PACKAGE__->run(@ARGV) unless caller;

Moving all of the code into another file (and using subroutines) messed with caller a bit. Now I had to look back a couple of levels to see what was going on. That seems simple now that I’ve figured it out, but on the way I loaded Modulino::Base in many ways and looked at caller going two levels back to convince myself I was doing the right thing. As with most coding problems, the other weird things I was trying to do had clouded the problems and simplifying the module solved it.

The danger with any code written specifically for a book is that it hasn’t been used widely and its problems haven’t appeared. I know they are there. Not only that, once the book is done, the author tends to stop supporting the code. I certainly plan that because I think the idea is simple enough that no one should use a module for it. That is, no one should create an external dependency to get something so simple.

I’ve also expanded the modulino idea. Previously, it was about running as a program or loading as a module. However, we can do other things based on any condition. The module can run as a test script. Modulino::Base looks for methods that start with _test_ and runs them as subtests if CPANTEST is set to a true value. I stole that idea from Python, although it doesn’t seem to be as popular as it was when I learned that language.

Beyond that, I experimented with having a module file be a template for its own documentation. Using some switch to say I wanted to read the docs, it ran Pod::Perldoc on itself, making modifications to the Pod along the way, such as automatically inserting the right package name. I like that idea and I think there’s more behind it, but it’s not something I want to delay the book for.

You can check out this chapter in O’Reilly Atlas.

Updated scriptdist

I’m amazed how much has changed in ten years.

I have a program to create a Perl module-like distribution around a standalone program. I used it back in the day when I wasn’t creating modulinos from the start, and in 2004 I wrote about it for The Perl Journal (which is now Dr. Dobbs Journal) as Automating Distributions with scriptdist.

I don’t use this much anymore, but it’s probably still useful for people stuck with many standalone legacy programs, so I updated it to version 0.22. In previous versions, which I created ten years ago, I was still using CVS. I’ve changed the program to automatically init and populate a git repo.

How I waste my time while writing

I’ve been keeping track of how I spend my time working on Mastering Perl. Most of that time is tracking down bugs in CPAN modules. For instance, to write two paragraphs about TryCatch for the Detecting and Reporting Errors” chapter, I’ve spent about seven hours trying to figure out why this seemingly trivial example doesn’t work (RT #87128 ):

use v5.10.1;
use TryCatch;

try {
	die "This died"
	}
catch {
	say "Caught [$@]";  # $@ is always blank
	}

As usual, I should have started with the RT queue to see if someone had already reported the bug. I found that it was reportedly as part of RT #49072.

This is not a huge problem. If you are using TryCatch, you probably want the advanced features to catch errors by type or you want to specify your own variable:

use v5.10.1;
use TryCatch;

try {
	die bless {}, 'Local::Foo';
	}
catch (Local::Foo $err) {
	say "Caught Local::Foo [$err]";
	}
catch ($err) {
	say "Caught [$err]";
	}

I first tried this on v5.18 and I had trouble installing it as Package::Stash and Package::Stash::XS seemed to have an unmet circular dependency such that I had to force install one of them to get the dependency-heavy TryCatch to install. Since I wanted to test several versions, I had to handle this five times and wait close to an hour for it to install in all versions on my puny laptop. All of that got me no further than reporting the bug to RT.

When I embark on these explorations, I don’t think I’m setting out for an adventure and an answer always seems right around the corner. The solution is always right around the corner and I want to try one more thing; every thing I try makes it more elusive.

I’ve also starting patching some distributions, then realizing they use Dist::Zilla, which means many things aren’t where they will finally show up and I’d have to install a very heavy tool to do very basic things. I’m really sad that people are cutting off so many people from submitting patches; the casual user who isn’t a module maintainer isn’t going to suffer the installation of tools and learning where to find things just to make a quick patch. It’s a couple times a week that I abandon a patch for this reason. I don’t even bother to send the problem to RT because I figure I’ve already wasted enough time, and if I can’t make the patch, I’m disinclined to bother with a report. If I were going to use the module for work, things might be different, but I’m just writing about them.

Mastering Perl is available for pre-order

Mastering Perl is available on Amazon.com for advance orders. It’s $1 less than the previous edition, too. You can also pre-order it directly from Oreilly.com, which gets you access to the in progress digital version of book as an “Early Release”.

I still think it’s roughly four months from actually showing up at your door though; I have a couple of chapters to finish.

New to “Symbol Tables”

“Symbol Tables” has always been a tough chapter because it’s the part of the book where I have the least experience, I think. I’m not strong on Perl internals and don’t have to think about symbol tables so much; my terminology is a bit soft and pudgey here.

For the most part, the chapter is the same without major changes. I use the word “stash” much more, flesh out some examples, and show the output of more programs.

I made a mistake in the previous edition. I had a subroutine that would check for that a package variable had been used somewhere in the program. I can do that with something like:

print "Used!\n" if *foo{ARRAY};

The typeglob will return a reference to the data for that variable, and references are always true values. If @foo hasn’t been used (so, no data yet, even if it’s the empty list), this returns undef. It returns true even if I’ve undef-ed the array; I’ve still used the array already in that case.

However, for scalars, it always returns a reference. It even returns a reference in the case that the scalar of that name has not ever been used or seen. The means *foo{SCALAR} is true for all names all the time. perlref says:

*foo{THING} returns undef if that particular THING hasn’t been used yet, except in the case of scalars. *foo{SCALAR} returns a reference to an anonymous scalar if $foo hasn’t been used yet. This might change in a future release.

Besides that, I made adjustments for imprecisions in my previous explanations and terms. I could use a good set of tech reviewers on it still.

At the end of the chapter, after showing all of the complicated stuff, I show Package::Stash, which mostly makes it easier to do the really hard stuff.

Check out this chapter in O’Reilly Atlas.

New to “Benchmarking”

Computers are much faster eight years later so my benchmark sample results are much faster. I’m regenerating those results with v5.18. I’ve tweaked many of the programs to be a bit more useful; in the previous edition I hardcoded values, such as the number of iterations. Now I can specify those on the command line.

Several of the benchmarks dealt with listing files with glob. In the first edition, I used a couple of existing directories. This time around, I spent too much time looking for suitable directories with the right numbers of files. After awhile, I gave up on that and had the programs create temporary directories with the number of files I specify:

use File::Temp qw(tempdir);
my $dir = tempdir( CLEANUP => 1 );

chdir( $dir ) or die "Could not change to $dir: $!";
foreach ( 1 .. $files ) {
    open my($fh), '>', "$0.$_.tmp" or die "Could not create a file: $!";
    print { $fh } time();
    }

After I covered Benchmark, I also mentioned Steffen Müller’s Dumbbench (see my earlier post, Playing with Dumbbench).

I updated the section on perlbench, Gisle Aas’s tool to compare benchmarks across different interpreters. Since he hasn’t updated that since I wrote the first edition, I took all of the previous releases and imported them into git so I could fix RT 73642, which recognizes the new way that perl reports its version. That’s now in my perlbench GitHub project.

Most of the other stuff is the same, with minor updates.

Check out this chapter in O’Reilly Atlas.

Looking for technical reviewers

I’m looking for technical reviewers for Mastering Perl. I’ve updated most of the book now, so the next part of the process is the technical review where people find all my lies and omissions. If you are interested, please send me email and I’ll give you the details. For your troubles, I’ll at least get you a free copy.