Modules & CPAN

Perl Intermediate/Advanced — 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 Handlingdie/eval, $@, and modern try/catch (Perl 5.34+).