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.
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*
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.