I've seen obfuscated and golfed code that keeps is off to avoid declaring variables, and I can see skipping them on the command line with the -e switch to keep the one-liner shorter. What are some cases where you would not want to use strict
and/or use warnings
in production code? What are reasons you would not want to use them?
The question comes up because I've seen posts on here where experienced Perl users tell people who are new to Perl to always use them.
I did find some related questions on here but they don't explain cases where we might want to keep them turned off.
The strict
pragma restricts you to a sane subset of Perl. Some old features make historic sense (or have benefits with one-liners), but have no place in a modern, readable code base.
The strict
pragma has three categories:
"vars"
Forces you to declare all your variables. This shields against typos, and makes sure you pick a scope (global/lexical). In a one-liner, this is not needed that much, as there are usually very few scopes, and very few variables. Some one-liner idioms wouldn't work with lexical variables only.
"refs"
disallows symrefs. They make no sense with lexical variables, and Perl5 has real references. So they are generally useless. However, symrefs remain valuable for metaprogramming:
# generate accessors
for my $field (qw/foo bar baz/) {
no strict 'refs';
*{ __PACKAGE__ . '::' . $field } = sub { shift()->{$field} };
}
"subs"
forces the interpretation of most barewords as subroutine calls. This resolves the ambiguity of foo . "bar"
to be foo() . "bar"
. If this category is not activated, and if no foo
sub is currently defined, then it would have parsed as "foo" . "bar"
. This makes sense to a shell programmer, where all barewords are strings. But in a Perl program, this drastically increases the cognitive load of the programmer, and is not worth it.
Summary: for simple scripts that don't optimize for readability, strict "vars"
isn't really neccessary. There are a few cases where no strict 'refs'
is desired.
The warnings
pragma allows fine grained control over warning messages. This is especially important for programmers new to Perl, who frequently write stuff like
my %hash = { foo => 1, bar => 2 };
and wonder where that HASH(0x1234567)
key came from. Even on a one-liner, warnings are desirable, except in cases where you use stringification of undef
etc.
In a professional codebase, there is no excuse for not using warnings
everywhere. If a script warns, it's very likely there is a bug, and no warnings
does not make this bug go away. Your knowledge of Perl is never as vast as that of the warnings
pragma. Even gurus make mistakes. use warnings
is a great debugging shortcut.
That said, it may be allright to comment the use warnings
when deploying the program. But never for development.
Depending on the consensus in the dev team, other pragmas should be used as well:
no indirect
disallows the loathed new Foo
method calls. I've seen bugs sneak in that could have been caught at compile time with this pragma.no autovivification
prevents references springing into existence on read-only operations like $hash{doesnt_exist}{foo}
.Sometimes strict
and warnings
prevent you from doing things you want to do, like doing certain manipulations on the symbol table that would violate strict 'refs'
, or redefining a subroutine where warnings 'redefine'
would be triggered. At other times it is more convenient to ignore certain warnings than to write defensive code against them, like a quick-and-dirty database dump for a table that might contain NULL/undef
values that would trigger warnings 'uninitialized'
.
use strict
and use warnings
, and their retardants no strict
and no warnings
can be locally scoped, so it is a best practice to disable strict
and warnings
in the smallest practical scope.
@data = get_some_data_from_database();
if (some_condition()) {
no warnings 'uninitialized';
logger->debug("database contains: @$_") for @data;
## otherwise, suppressing the warnings would take something
## less readable and more error-prone like:
# logger->debug("database contains: @{[map{defined?$_:''}@$_]}") for @data
# logger->debug("database contains: @{[map{$_//''}@$_]}") for @data
}
# end of scope, warnings `uninitialized' is enabled again
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With