简体   繁体   中英

Why not use strict and warnings in 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.

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" foo . "bar" to be foo() . "bar" foo() . "bar" . If this category is not activated, and if no foo sub is currently defined, then it would have parsed as "foo" . "bar" "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

Doing use strict and use warnings helps someone understand exactly what Perl is doing.

Someone who understands exactly what Perl is doing and why, all of the time (ie, pretty much nobody), would qualify for omitting them in order to save space and possibly execution time. Unfortunately, many of the people who want to save space and time are those who don't know exactly what Perl is doing and why, and their understanding of what Perl is doing is based on so many false assumptions learned from other languages, that they should absolutely never be allowed to omit them.

There are some other valid reasons as well:

  • experimenting with behavior that would produce a warning that you are already fully aware of (eg, a lot of recursion)
  • using old packages (although any of my packages written after about July, 2000 still produce no messages with either use strict or use warnings , so "old" here means really, really old, like Perl version 4 or older)
  • when you want to take advantage of magical Perl behavior that no one would expect (but which you do expect because you are an expert) and don't want to pay the price of a warning for doing so

By the way, for programs accepting any input and performing actions on the basis of that input, it is also very important to use the -T flag to help track the use of possibly tainted data obtained from user input.

Update: @mob makes a claim in a comment that bears some investigation, ie, that not using strict and warnings is a micro-optimization below the point of even average insignificant microptimizations. In every case below, the real time for not using strict and warnings is 12 milliseconds, and in every case below, the real time for using them is 57 milliseconds or more.

So there is, just as I said originally, a possible benefit in execution time (that would only matter if you were doing something like embedding Perl scripts within templates and running 10 or 20 of them at a time every time a web page was loaded, for example), but it is still recommended that you use them unless you truly know exactly what Perl is doing and why, all of the time. My description of this category of "experts" is intended to be very close to the empty set. If you think you fall into this category, you automatically don't.

[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.005s
sys     0m0.007s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.010s
sys     0m0.005s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.011s
sys     0m0.001s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.004s
sys     0m0.007s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.005s
sys     0m0.007s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.058s
user    0m0.058s
sys     0m0.000s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.041s
sys     0m0.016s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.033s
sys     0m0.025s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.050s
sys     0m0.009s

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM