Smoke-Test a Perl 5.38 Upgrade Before You Ship
Perl 5.38 changed more than a version number, and the traps are easy to miss until they bite in production. This guide runs a small set of checks in about 15 minutes: confirm the interpreter version, exercise the new experimental class syntax, prove PERL_RAND_SEED actually works, and surface deprecation warnings that may affect you, before you run your own application's tests on top.
The route
Jump straight to the step you need, or tick off Done means at the end.
The local manual page describes the change from Perl 5.36.0 to 5.38.0. The interpreter installed here is Perl v5.38.2, built for x86_64-linux-gnu-thread-multi. Patch releases can differ in the details, so record the exact result from your own machine before comparing it against a deployment host.
1. Record the interpreter you are testing
Start with a read-only version check, run as the same account that will run the application. Do not reach for sudo just to inspect Perl.
$ perl -v
This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi
$ perl -V:version -V:archname
version='5.38.2';
archname='x86_64-linux-gnu-thread-multi';
Your patch level and architecture may differ. Stop here if the service's interpreter is not the one you meant to upgrade, a shell's PATH can select a different Perl from the one a service actually launches, so check the service's launch environment separately.
Checkpoint
Save the version and architecture with the application's test report. It gives you something to compare against if a later failure only shows up on one host.
2. Exercise the new class syntax in isolation
Perl 5.38 adds an experimental class feature: a class can declare per-instance field variables and methods. It is not a stable replacement for an established object system, the manual says the feature stays experimental and warns in the experimental::class category.
Put this in a temporary file or pass it to perl -e. It creates an object, changes both fields through a method and prints a result; the no warnings line is deliberate and local to this experiment only.
$ perl -e 'use feature "class"; no warnings "experimental::class"; class Point { field $x; field $y; method zero { $x = $y = 0 } }; my $p = Point->new; $p->zero; print "class-ok\n"'
class-ok
Keep experimental warnings on in normal development unless you have reviewed and accepted the feature. Suppressing them globally can hide a future compatibility warning. To see the warning on this interpreter, drop no warnings "experimental::class" and run the same compile check:
$ perl -we 'use feature "class"; class Point { field $x; method zero { $x = 0 } }'
class is experimental at -e line 1.
field is experimental at -e line 1.
method is experimental at -e line 1.
The exact line numbers and warning order are not an interface you can rely on. What matters is that the code compiles on your target interpreter and the warnings show up when you have not opted out.
3. Test repeatable random output without changing application code
Perl 5.38 introduces PERL_RAND_SEED, which can make code that calls rand without an explicit seed, or srand without an argument, repeatable. Handy for a focused test run. Not a source of secrets, and not a substitute for a cryptographic random generator.
Run the same short program twice with the same environment value, then once with a different one:
$ PERL_RAND_SEED=12345 perl -e 'print join(" ", map { rand() } 1..3), "\n"'
0.225328512796299 0.919183068533556 0.206841253248182
$ PERL_RAND_SEED=12345 perl -e 'print join(" ", map { rand() } 1..3), "\n"'
0.225328512796299 0.919183068533556 0.206841253248182
$ PERL_RAND_SEED=54321 perl -e 'print join(" ", map { rand() } 1..3), "\n"'
0.0230370595390958 0.808510160629766 0.197774572801915
Warning
Compare complete output in a test rather than copying these particular numbers into a portability test, the sequence is tied to Perl's implementation and version. Never set this variable in a production process that needs unpredictable values, and do not mistake repeatability for security.
4. Turn deprecations into actionable test failures
Perl 5.38 gives deprecation warnings their own subcategories, and smartmatch is the obvious upgrade trap: its experiment was declared a failure in this release, and the manual says the feature is planned for removal in Perl 5.42. Existing code using ~~ still runs in 5.38, but it should be found and replaced rather than hidden.
$ perl -we 'my $same = 1 ~~ 1; print "same=$same\n"'
Smartmatch is deprecated at -e line 1.
same=1
For a codebase, make warnings visible during the test command and search source and generated code for the operator:
$ rg --glob '*.pl' --glob '*.pm' '~~' lib bin t
$ PERL5OPT=-Mwarnings prove -lr t
Do not edit every match mechanically. Smartmatch behaves differently depending on context, so replace each use with the comparison that actually expresses its intended types and data shape. Treat the warning as a review queue, not permission to disable the deprecated category.
5. Check the 5.38 I/O compatibility edge
One change worth adding to tests that reuse filehandles: in 5.38, readline(), also written <>, normally leaves the stream's error and end-of-file flags set after an error or end of input. If code rebinds the handle to another descriptor or expects to read again, call $handle->clearerr() at the deliberate recovery point.
This especially matters to modules using non-blocking descriptors. A failed read can set the error flag, and a later close() can then fail or warn. Check the return values from both operations and test the recovery path with the same descriptor type used in production. Do not add clearerr() blindly after every read, clearing a real error can discard information your caller needs.
The manual's other compatibility changes include earlier compile-time rejection of forbidden control flow out of defer or finally, and fewer follow-on diagnostics after a syntax error. A failed compile is not evidence that every old diagnostic should still appear, so assert success or failure and the useful part of the diagnostic, not a whole historical error transcript.
Done means
- Recorded the exact Perl version and architecture used by the target process.
- Compiled the experimental class check, with any warning suppression explicit and local.
- Confirmed
PERL_RAND_SEEDrepeatability: same seed, same sequence; different seed, different sequence. - Made smartmatch and other deprecation warnings visible in the test run, with an owner assigned for replacement.
- Added a deliberate
clearerr()recovery test for code that reuses filehandles after EOF or read errors. - Kept the whole check unprivileged: no root, no service changes, no production data touched.