Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why not use strict and warnings in Perl?

Tags:

perl

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.

like image 627
hmatt1 Avatar asked Aug 05 '13 17:08

hmatt1


Video Answer


2 Answers

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}.
like image 176
amon Avatar answered Nov 15 '22 14:11

amon


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
like image 38
mob Avatar answered Nov 15 '22 13:11

mob