My favourite Perl Design Pattern

Alias on 2009-11-05T01:26:22

Design Patterns have been an on-again, off-again fad for a while now. Statements like "Perl doesn't need Design Patterns, we have the CPAN" are common because most of the well-known patterns come from Java, where you can't do much of anything without 100 lines of structural boilerplate.

But a design pattern, at it's core, is a method for solving a particular problem that can't be done using a language's native structures and can't be (elegantly) solved as a module.

For example, Class::Adapter is my CPAN module for implementing the "Adapter" pattern from the gang of four book. An Adapter may be a pattern in Java, but it doesn't really rate being called such in Perl.

So I'd like to issue this blog challenge.

I want to see a post on your favourite Perl Design Pattern, some technique or trick that can't be done elegantly with Perl's native language resources, isn't so small that it might be classed as an idiom, and can't be easily packed up into a CPAN module.

I'll happily kick things off by presenting mine, the "Constant Global" (Haskell people might call it the Curried Global, which admit has quite a ring to it)

I use it all the time for debugging and tracing.

A Constant Global is a combination of global variable and a constant which is useful for debugging, assertions, and other situations where you want to add optional functionality to a very performance-sensitive module, so a feature can be enabled (or disabled) from outside that module.

The code for the canonical debugging version looks like this... package My::Module;

use strict; use vars qw{$DEBUG}; BEGIN { $DEBUG = !! $DEBUG; } use constant DEBUG => $DEBUG;

sub foo { print STDERR "Running foo" if DEBUG; }

1;


This usage allows you to define variables in your top level script or test that will turn features on or off before you load the module, without incurring the penalty of all those if ( ... ) { ... } statements, since they will be compiled out.

Loading the module will look something like the following... #!/usr/bin/perl

BEGIN { $My::Module::DEBUG = 1; }

use My::Module;


Now, you only get one chance to choose if a feature will be enabled or disabled, so most use cases will either be debugging, and testing special cases, or features in modules which you would never really use twice, differently, in two different places in your code.


Meta programming

nothingmuch on 2009-11-05T09:05:56

I think Perl has continually defied these attempts to package patterns because of it's meta programmability.

Things we previously thought were not possible to package are now on CPAN as usable modules.

Design patterns are thus getting more and more refined, and in time converge simply with the best practices for the software that helps to implement them.

In the Java community metaprogramming is a much more difficult thing, so in order to produce extensible, reusable and clean code you need to have a much stricter methodology.

Re:Meta programming

nothingmuch on 2009-11-05T10:33:55

bah, i meant attempts to *define*

Badger::Debug

abw on 2009-11-05T11:33:27

<plug>

I also use the $DEBUG/DEBUG idiom in pretty much every module I write.  Being rather lazy I wrote Badger::Debug to do the job for me.

If you add the following to the top of your module:

    package Your::Module;
    use Badger::Debug default => 0;

Then you'll get both the $DEBUG package variable and DEBUG compile time constant defined for you (in this case, set to 0). The end result is almost exactly as per your example.

It also has a 'modules' option which you can use to enable debugging in various modules of your choice.

    use Badger::Debug modules => 'Your::Module';
    use Your::Module;

Now both $DEBUG and DEBUG will be set to 1 when Your::Module loads.

See http://badgerpower.com/docs/Badger/Debug.html#section_SYNOPSIS for further information.

Badger::Debug also plays nicely with Badger::Class.  This implements a number of useful idioms/patterns that I/we tend to use a lot.  For example:

    package Your::Module;

    use Badger::Class
        version   => 0.01,            # set $VERSION and VERSION
        debug     => 0,               # set $DEBUG and DEBUG
        base      => 'Badger::Base',  # set base class
        accessors => 'foo bar',       # define accessors
        mutators  => 'wam bam',       # define mutators
        utils     => 'blessed',       # import from [Scalar|List|Hash]::Util
        constant  => {
            PI    => 3.14159,         # define PI
        };
        # ...and so on...

All the above is "boring stuff" - supporting code that doesn't really relate to the core functionality of a module.  I don't like littering the first 100 or so lines of a module with various idiomatic bits of boilerplate code before I can get started on coding proper.  So  Badger::Class's raison d'etre is to sweep all that crufty stuff out of the way and hide it behind a nice simple interface.

</plug>

Higher-Order Perl as a catalog of design patterns

Dominus on 2009-11-05T18:04:51

I have a semi-finished blog post sitting around that interprets much of the content of HOP as a catalog of design patterns for Perl. Chapter 4 is probably the best example. Most of that chapter is concerned with methods of implementing generator functions that enumerate large quantities of data, one element at a time.

Your pattern *is* implemented in a CPAN module

btilly on 2009-11-05T22:24:15

See ifdef.

In response to the criticism that it is a source filter, it filters for content within pod sections, which avoids almost all of the ambiguities that otherwise make parsing Perl so fun.

Re:Your pattern *is* implemented in a CPAN module

chocolateboy on 2009-11-07T02:17:45

Oh, that's ridiculously cool. Thanks for the link.