Perl::...rscore(3pm)
๐ Perl::Critic::Policy::Compatibility::ConstantLeadingUnderscore ๐
okay bestie, so this page is straight out of the User Contributed Perl Documentation section of the manual, and its full government name is Perl::Critic::Policy::Compatibility::ConstantLeadingUnderscore. It's filed under Perl::...rscore(3pm) because man page titles get truncated and honestly that's giving chaos but we move. ๐ซถ
โจ NAME โจ
Perl::Critic::Policy::Compatibility::ConstantLeadingUnderscore โ it's giving "new enough constant module for leading underscores". That's the whole vibe of the policy, no notes. ๐ธ
๐ DESCRIPTION ๐
So this policy is part of the Perl::Critic::Pulp add-on, and what it does is: if you've got a constant with a leading underscore like this โ
use constant _FOO ... # leading underscore on name
โ then it wants you to explicitly say use 5.6 or use constant 1.02, or higher. Why? Because back in the day, constant.pm straight up did not allow leading underscores. Ancient behavior, iconic for all the wrong reasons. ๐ญ
Watch the glow-up:
use constant _FOO => 123; # bad
use 5.006;
use constant _FOO => 123; # ok
use constant 1.02;
use constant _FOO => 123; # ok
use constant 1.02 _FOO => 123; # ok
The whole point is protecting you from trouble in code that might run on Perl 5.005, or might in principle still run there. Which is why this policy lives under the "compatibility" theme โ see "POLICY THEMES" in Perl::Critic. ๐
And asking for the new-enough module use constant 1.02 is the suggested move, because it's the module feature that's actually required here. That way your code might still run on Perl 5.005 or earlier as long as the user has a suitable constant.pm from CPAN. Fancy, flexible, slay. โจ
๐ Details
A version declaration has to come before the first leading underscore, so it gets checked before the underscore is even attempted (which would throw an error and ruin everyone's day).
use constant _FOO => 123; # bad
use 5.006;
A require for the Perl version is not enough, periodt, because use constant happens at BEGIN time โ before plain code even exists yet.
require 5.006; # doesn't run early enough
use constant _FOO => 123; # bad
But a require inside a BEGIN block? Totally fine. (It's a past style โ still spotted in the wild occasionally, like a vintage find at the thrift store. ๐ฆ)
BEGIN { require 5.006 }
use constant _FOO => 123; # ok
BEGIN {
require 5.006;
and_other_setups ...;
}
use constant _FOO => 123; # ok
ngl, there's a caveat: right now ConstantLeadingUnderscore pays no attention to any conditionals within the BEGIN. It just assumes any require in there always runs. Could it be tricked by obscure tests? Maybe. But hopefully anything like that is rare, or does the right thing anyway. ๐
A quoted version number like
use constant '1.02'; # no good
is no good โ only a bare number is recognised by the use statement as a version check. A string like that actually gets passed through to constant as a name to define... and constant will reject it. Not the moment. ๐
Leading underscores inside a multi-constant hash are not flagged, because a constant.pm new enough to have multi-constants is already new enough to have underscores. Simple math, bestie. See Compatibility::ConstantPragmaHash for the multi-constants version check.
use constant { _FOO => 1 }; # not checked
Leading double-underscore is disallowed by all versions of constant.pm. This policy doesn't report it though, since the code won't run at all. It's not a compatibility issue, it's a whole funeral. ๐
use constant __FOO => 123; # not allowed by any constant.pm
๐ฎ๐จ Drawbacks
Okay real talk: explicitly adding required version numbers in your code can be irritating, especially if everything else you're doing only runs on 5.6 and up anyway. But โ and hear me out โ declaring what the code needs is accurate, it leaves room for backports of modules, and explicit versions can be grepped out to create or check Makefile.PL or Build.PL prereqs. Iconic engineering behavior. ๐
And as always: if you don't care about this, or you only ever use Perl 5.6 anyway, you can disable ConstantLeadingUnderscore from your .perlcriticrc in the usual way โ see "CONFIGURATION" in Perl::Critic:
[-Compatibility::ConstantLeadingUnderscore]
๐ OTHER WAYS TO DO IT ๐
It's genuinely easy to write your own constant sub, and it can have any name at all (anything acceptable to Perl), completely bypassing the sanity checks or restrictions in constant.pm. The only catch is that the () prototype is a bit obscure. Just a lil mysterious. ๐ง
sub _FOO () { return 123 }
The key benefit of subs like this โ whether they come from constant.pm or from you being extra โ is that the value gets inlined and can be constant-folded in an arithmetic expression etc. See "Constant Functions" in perlsub.
print 2*_FOO; # folded to 246 at compile-time
The purpose of a leading underscore is normally a hint that the sub is meant to be private to the module and/or its friends only. Group chat, not public post. ๐
If you don't need the constant folding, then a my scalar is even more private โ it's invisible to anything outside the relevant scope:
my $FOO = 123; # more private
# ...
do_something ($FOO); # nothing to constant-fold anyway
Also! The scalar returned from constant.pm subs is flagged read-only, which might prevent accidental mis-use when passed around. The Readonly module gives the same effect on variables. And if you have Readonly::XS, then it's just a flag too (no performance penalty on using the value). Best of both worlds honestly.
use Readonly;
Readonly::Scalar my $FOO => 123;
๐ SEE ALSO ๐
Perl::Critic::PulpPerl::CriticPerl::Critic::Policy::Compatibility::ConstantPragmaHashPerl::Critic::Policy::ValuesAndExpressions::ProhibitConstantPragmaPerl::Critic::Policy::Modules::RequirePerlVersionconstant- "Constant Functions" in perlsub
๐ HOME PAGE ๐
<http://user42.tuxfamily.org/perl-critic-pulp/index.html>
๐ COPYRIGHT ๐
Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2021 Kevin Ryde
Perl-Critic-Pulp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.
Perl-Critic-Pulp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
๐ซถ that's the whole page, bestie. no cap, we covered every flag-free, option-free, gloriously detailed inch of it. ๐
and that's a wrap on this one, bb โ this copy came from perl v5.40.1 dated 2025-10-21, so if you're reading this from the future, hi, you're gorgeous, check for a newer version. ๐ฆโจ
๐ฆ where this page comes from
- ubuntu resolute: libperl-critic-pulp-perl 100-1 ยท GPL-3.0-or-later
- ubuntu stonking: libperl-critic-pulp-perl 100-1 ยท GPL-3.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms