Modules & CPAN

Perl Intermediate/Advanced
Course 2 ยท Chapter 5 ยท Modules & CPAN

๐Ÿ“ฆ Modules & CPAN

Course 1, Chapter 1 briefly mentioned Strawberry Perl shipping cpanm. This chapter covers the full picture: loading existing modules properly, writing and exporting your own, and CPAN itself โ€” one of the oldest, largest package ecosystems in programming, predating both npm and PyPI's modern form by well over a decade.

๐Ÿ“ฅ use vs. require

use List::Util qw(max min sum);   # compile-time loading, imports specific symbols immediately
say max(3, 7, 2);                     # 7 โ€” used directly, no package prefix needed

require List::Util;                    # runtime loading, no automatic import
say List::Util::max(3, 7, 2);           # must fully qualify, or call ->import() manually

use is what you want for essentially all real code โ€” it loads the module and imports its exported symbols at compile time, before the rest of the script even runs. require loads at runtime instead, with no automatic import โ€” genuinely useful for the rarer case of conditionally loading a module based on logic that can't be known until the script is actually running.

โœ๏ธ Writing Your Own Module

# Utils.pm
package Utils;
use strict;
use warnings;

sub shout {
    my ($text) = @_;
    return uc($text) . "!";
}

1;   # required โ€” see this chapter's own warn-box

This reuses Chapter 3's package declaration directly โ€” a module is just a package, conventionally saved in a file matching its name (Utils.pm for package Utils;).

โš  A .pm File Must End With a True Value

When use or require loads a file, Perl checks the file's last evaluated expression โ€” if it isn't true, loading fails with Utils.pm did not return a true value. The trailing 1; is a plain true value placed deliberately as the file's final statement, purely to satisfy this requirement. Forgetting it is a genuinely common first-module mistake โ€” the module's actual code can be entirely correct and still fail to load.

๐Ÿ“ค Exporting Symbols with Exporter

# Utils.pm
package Utils;
use Exporter 'import';
our @EXPORT_OK = qw(shout);   # available, but NOT imported unless explicitly requested

# calling script:
use Utils qw(shout);
say shout("hello");   # HELLO!

@EXPORT_OK lists symbols available for opt-in import โ€” the calling script must explicitly request them (use Utils qw(shout);). This is the recommended practice over the older @EXPORT, which exports everything listed unconditionally into every script that uses the module โ€” a real risk of silently colliding with the caller's own subroutine or variable names. Explicit opt-in keeps namespace pollution under the caller's control.

๐ŸŒ The CPAN Ecosystem

CPAN (the Comprehensive Perl Archive Network) launched in 1995 โ€” genuinely one of the oldest centralized package repositories in programming, predating npm (2010) and PyPI's modern form by well over a decade. It's a significant part of why Perl became so practically useful early: an enormous, searchable library of community-published modules for nearly anything.

cpanm List::Util          # cpanm (App::cpanminus) โ€” the modern, simple CPAN client
cpanm --installdeps .     # install everything listed in a project's cpanfile

A cpanfile declares a project's dependencies โ€” the direct Perl parallel to Course 1, Chapter 9's Python requirements.txt or Node's package.json.

โญ A Few Genuinely Useful CPAN Modules

ModuleWhat it's for
Path::TinyThe nicer file-handling wrapper previewed back in Course 1, Chapter 8 โ€” read/write a whole file in one call
JSON::PPJSON encoding/decoding โ€” actually part of Perl core since 5.14, no install needed
Try::TinyA cleaner error-handling syntax, previewed ahead of Chapter 6
DateTimeRobust date/time handling, well beyond localtime's context-sensitive quirkiness from Chapter 2

๐Ÿ”ง A Worked Example โ€” A Small Module

# MathUtils.pm
package MathUtils;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT_OK = qw(square cube);

sub square { my ($n) = @_; return $n * $n; }
sub cube   { my ($n) = @_; return $n * $n * $n; }

1;
# script.pl
use strict;
use warnings;
use feature 'say';
use MathUtils qw(square cube);

say square(4);   # 16
say cube(3);     # 27

CPAN vs. pip/npm

The underlying model is the same across all three โ€” a central registry, a simple install command, community-published packages. The real difference is age and culture: CPAN's 1995 launch makes it genuinely older than npm or PyPI's current form by well over a decade, and it fostered a "there's already a well-tested module for this" culture in Perl development early โ€” much of the reason Perl earned a reputation as a practical, get-things-done language for real work, not just an academic one.

use vs require

Compile-time with automatic import, vs. runtime with none.

The trailing 1;

Every .pm file must end with a true value or loading fails.

@EXPORT_OK

Opt-in exporting โ€” safer than unconditional @EXPORT.

cpanm / cpanfile

The modern CPAN client, and a project's declared dependencies.

๐Ÿ’ป Coding Challenges

Challenge 1: Write and Use a Module

Write a module StringUtils.pm exporting a subroutine reverse_string via @EXPORT_OK. Write a separate script that uses it and prints the result of reversing "Perl".

โ†’ Solution

Challenge 2: Diagnose the Missing 1;

Given a module file whose last line is a subroutine definition (with no trailing 1;), explain in one sentence what error occurs when a script tries to use it, and show the corrected final lines.

โ†’ Solution

Challenge 3: use vs require

Write two versions of loading and calling List::Util's max function on the list (3, 9, 4) โ€” one using use with a qw() import list, one using require with a fully-qualified call โ€” and explain in one sentence the key difference between them.

โ†’ Solution

๐ŸŽฏ What's Next

Next chapter: Error Handling โ€” die/eval, $@, and modern try/catch (Perl 5.34+).