Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Why use warnings? -w

by harangzsolt33 (Chaplain)
on Feb 22, 2018 at 04:56 UTC ( [id://1209716]=perlquestion: print w/replies, xml ) Need Help??

harangzsolt33 has asked for the wisdom of the Perl Monks concerning the following question:

What do the "use warnings;" and "use strict;" statement do exactly? So far I have noticed that when I try to use an uninitialized variable, it gives me a compilation error. That's NO BIG DEAL, I think. I mean, we're told in Perl tutorials, that we don't have to initialize variables in Perl. We can just start using them. Right? Just like in JavaScript or QBASIC.

So, WHAT EXACTLY HAPPENS IF I START USING UNINITIALIZED VARIABLES IN PERL? And why are people saying that we shouldn't get in the habit of doing this? In JavaScript, an uninitialized variable automatically becomes a global variable when we use it. So, if I refer to A in my function, then when I type "A = 5" it becomes a global variable. But if I initialize it as "var A = 5" then it becomes a temporary variable that exists only within the scope of that function. Is Perl treating variables the same way?

What else happens if I quit using the "warnings" and "strict"? Is there any other trouble that may arise? ARE MY PERL SCRIPTS GOING TO RUN SLIGHTLY FASTER IF I DON'T USE STRICT AND WARNINGS? I am just trying to think of all the pros and cons, but so far all I've heard is that you got to use these two. But I don't know why. I want to understand the whys.

Replies are listed 'Best First'.
Re: Why use warnings? -w
by davido (Cardinal) on Feb 22, 2018 at 06:43 UTC

    To clarify, the "Use of uninitialized value in..." warning is a runtime warning, not a compilation error, and it is not fatal by default. It is often useful because it alerts the developer to the fact that he or she is doing something with a variable that appears to be expecting it to contain a defined value, which it does not have. For example, consider the following code:

    use warnings; + + while (defined(my $line = <DATA>)) { + print "\n"; + chomp($line); + my ($k, $v) = split /\s*=\s*/, $line; + print "The $k key has $v value\n"; + output_flush(); + } + + sub output_flush { + # Keep our STDOUT and STDERR in sync with each other, and in itera +tion order: $_->flush for *STDERR, *STDOUT; + } + + __DATA__ + [main] + foo=bar + baz=buzz + + [config] + bingo=42

    The output will be as follows:

    Use of uninitialized value $v in concatenation (.) or string at mytest +.pl line 12, <DATA> line 1. The [main] key has value The foo key has bar value The baz key has buzz value Use of uninitialized value $k in concatenation (.) or string at mytest +.pl line 12, <DATA> line 4. Use of uninitialized value $v in concatenation (.) or string at mytest +.pl line 12, <DATA> line 4. The key has value Use of uninitialized value $v in concatenation (.) or string at mytest +.pl line 12, <DATA> line 5. The [config] key has value The bingo key has 42 value

    Why?

    On the first iteration the line read in is [main], which we try to split on '=', allowing for some whitespace. Since there is no = character, only the $k variable receives data, and $v remains undefined. This happens on two occasions through this example run. So here the warnings alert us that we're not gracefully handling lines that contain section headers ([main] and [config]). This is useful to know, because we might be doing something with this data that would lead to corruption in our results.

    On another line we see "The key has value", preceded by a couple of warnings. Those warnings came because we didn't gracefully handle a blank line. So again the warnings have now alerted us to something we should be better anticipating and dealing with, which could be skewing or corrupting our results.

    This is a pretty trivial example, but it's a common class of bugs. The purpose of the uninitialized warning is to let us know we are acting upon a variable as though we expect it to have a defined value, and instead it's value is undef. This may be fine, or may be a mistake. Imagine how much harder it would be to spot if $v contained a number, or undef, and that number were used in an equation that obscured the fact that it came in undefined.

    The undefined warning is at least smart enough to not complain when you do something like this:

    my $c; while ($c++ < 10) { print "$c\n"; }

    Here $c starts out undef, but is postincremented during the first comparison. And in fact, there are two warnings that are suppressed automatically in this example; the first is an uninitialized warning for numeric comparison. The second is uninitialized for the numerical addition (postincrement). Perl lets you do both of those in THIS context because they're a common idiom and usually not incorrect. However, in other cases where the intent isn't so clear Perl would complain about the relational comparison, and $c = $c + 1 would probably also warn.

    A full explanation of the purposes of strict and warnings is really more than I should be typing into a response here when there's good documentation already available. But the short and sweet explanation is that these are tools to help you discover bugs, and to make development work easier. They're not always useful, and can be turned off selectively if ever they get in the way of legitimate work.

    For additional information, see the following docs:

    strict, warnings, perllexwarn, perldata.

    There certainly are other documents in Perl's POD, but these will get you started, and will link to additional reading. In the end, yes, you can ignore warnings, and can even disable them or disable strictures, but for nontrivial code, doing so will probably increase development and debugging time, and may leave you with latent bugs you would have otherwise discovered quickly.


    Dave

Re: Why use warnings? -w
by dsheroh (Monsignor) on Feb 22, 2018 at 09:22 UTC
    Why do I use strict and warnings 99+% of the time? Because, when (not if!) I need to debug my code, they are my absolute best friends in the world. When I make an error in my code, strict tells me about it before the program even starts running! When I go to track down a strange, usually data-dependent, behavior, warnings finds anomalies and points me to a good starting point for identifying their causes. And all of this help comes at essentially no cost.

    As for why everyone always starts answers to "what's wrong with my program?"-type questions with an admonition to use strict and warnings, that's also because they're such important debugging tools. More often than not, if someone is asking a beginner-to-intermediate-level "what's wrong with my program?" question, all they have to do is turn on strict and warnings and Perl itself will tell them the answer to their question in less time than it takes to ask the internet for help.

    But I do agree with you that the use of uninitialized value warnings can be a bit overzealous at times.

    In JavaScript, an uninitialized undeclared variable automatically becomes a global variable when we use it. So, if I refer to A in my function, then when I type "A = 5" it becomes a global variable. But if I initialize it as "var A = 5" then it becomes a temporary variable that exists only within the scope of that function. Is Perl treating variables the same way?
    Yes, if you declare a variable with my in Perl, the variable exists only within the scope where it is declared. (Most of us around here would say that it is "lexically scoped".) And this is generally a Very Good Thing. Global variables aren't inherently bad, per se, but well over 95%, probably over 99%, of the variables I use (outside of one-liners) are lexically scoped. I never use a global variable without a compelling reason to do so.

    So why do people say you should avoid globals? Again, the answer is "easier debugging". A global variable exists everywhere throughout your entire program, which means that if you change it in one part, it can cause bugs in any other part, even if the change and the bug are in different source files or thousands of lines away from each other within the same file. Finding the cause of this kind of action-at-a-distance bug can be nearly impossible, but they happen very easily, requiring nothing more than thinking the same variable name is appropriate in two different places or even a simple typo to occur.

    In contrast, if you habitually use lexical ("my") variables and restrict each of them to the smallest possible scope, then the variable lives and dies, usually, within a short enough section of code that you can have its entire lifespan on your screen at once. There's no chance of it being invisibly modified elsewhere, because it doesn't exist elsewhere. If the same variable name is referenced somewhere else? No problem! Since it's a different scope, that's a completely separate variable which just happens to have the same name, so they won't interfere with each other.

      WOW.
      Very nice and easily to understand explanation.
      Thanks alot.
Re: Why use warnings? -w
by alexander_lunev (Pilgrim) on Feb 22, 2018 at 05:47 UTC

    I think that to use strict is a good programming practice, like sane variable naming, not using gotos and all of that. Just yesterday I found that debugging script without use strict is long and painful. Consider this typo in a more than 1000 lines of code script:

    my $places_labels = {}; # .... about 100 lines skipped while (my $p = $i->next) { $place_labels->{$p->id} = $p->name; }

    All you need to find such typo is to use strict.

    Perl, like Unix, will not stop you to shoot your own foot. You may not use strict if you know what you're doing.

    Warnings is similar to strict. If you want to make fast and ugly code that just works and hear no complains from perl - just don't enable them.

      "...not using gotos..."

      It depends. See Re^2: A meditation on the naming of perl6 ;-)

      Best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

        I don't see why you need goto there ;)

        #!/usr/local/bin/perl -w use strict; use warnings; use feature qw(say); $SIG{INT} = sub { die q(Nuff said!); }; say q(Did you post some valid code today?); my $answer; while (not defined $answer) { chomp( $answer = <STDIN> ); $answer = lc $answer; my %dispatch = ( 'yes' => sub { say q(Good!) }, 'no' => sub { say q(Bad!) }, 'nada' => sub { say q(Answer yes or no!); undef $answer; } ); ( $dispatch{$answer} || $dispatch{nada} )->(); }
Re: Why use warnings? -w
by hippo (Bishop) on Feb 22, 2018 at 09:44 UTC
Re: Why use warnings? -w
by Laurent_R (Canon) on Feb 22, 2018 at 10:32 UTC
    ARE MY PERL SCRIPTS GOING TO RUN SLIGHTLY FASTER IF I DON'T USE STRICT AND WARNINGS?
    Yes, in some cases at least, they will probably run slightly faster. Very slightly faster. In fact, so slightly faster that you probably won't be able to notice. And that will not be significant in probably more than 99.9% of the cases. If you have a program that runs in, say, 20 minutes, why should you care about saving a few seconds? In brief, this is really irrelevant.

    But that's most probably the wrong question to ask. IMHO, the right question is: will my program be developed and debugged faster if I do use strict and warnings? And, there, the answer is a big YES. Your program is very likely to be ready and working correctly earlier if you do use strictures. Quite often much earlier. Strictures can (and will) save you literally hours of useless debugging time, for example when you made a stupid typo on a variable name (and we all do that type of silly mistake), especially if your program has more than a few dozen lines.

    From an economic standpoint, developer's time is usually worth much more money than CPU time. Especially, an hour of developer's time is worth million times more than milliseconds or microseconds of CPU time. Save your own time, don't worry about silly micro-optimizations or your code.

    Update: Fixed a typo (s/if/is/) in the last paragraph. Thanks to 1nickt for pointing it out. And also a duplicate word in the first paragraph. Thanks to AnomalousMonk for noticing.

Re: Why use warnings? -w
by karlgoethebier (Abbot) on Feb 22, 2018 at 09:49 UTC

    From the friendly documentation:

    "The strict pragma disables certain Perl expressions that could behave unexpectedly or are difficult to debug, turning them into errors. The effect of this pragma is limited to the current file or scope block. If no import list is supplied, all possible restrictions are assumed. (This is the safest mode to operate in, but is sometimes too strict for casual programming.) Currently, there are three possible things to be strict about: "subs", "vars", and "refs"."
    "The warnings pragma gives control over which warnings are enabled in which parts of a Perl program. It's a more flexible alternative for both the command line flag -w and the equivalent Perl variable, $^W . This pragma works just like the strict pragma. This means that the scope of the warning pragma is limited to the enclosing block. It also means that the pragma setting will not leak across files (via use, require or do). This allows authors to independently define the degree of warning checks that will be applied to their module. By default, optional warnings are disabled, so any legacy code that doesn't attempt to control the warnings will work unchanged."

    See strict and warnings and Why use strict and warnings?.

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: Why use warnings? -w
by davido (Cardinal) on Feb 22, 2018 at 18:03 UTC

    I wanted to follow up despite having already posted in this thread, so that I can address some specific questions you ask more directly:

    WHAT EXACTLY HAPPENS IF I START USING UNINITIALIZED VARIABLES IN PERL?

    Perl's data types are polymorphic, and its operators are generally monomorphic. This contrasts with languages like C++ where operators are polymorphic and datatypes are monomorphic (though with carefully crafted parametric templates you can get away with treating data as generic, which isn't the same as polymorphic but often feels the same).

    Observe the following:

    use strict; use warnings; use Devel::Peek; no warnings 'uninitialized'; my $c; is_defined('Beginning state: $c is ', $c); Dump($c); print "\n$c\n"; is_defined('State after printing: $c is ', $c); Dump($c); print "\n", (0 + $c), "\n"; is_defined('State after integer operation: $c is ', $c); Dump($c); $c = 0 + $c; is_defined("\nState after assignment: \$c is ", $c); Dump($c); $c = undef; is_defined("\nState after assigning undef: \$c is ", $c); Dump($c); sub is_defined { my ($msg, $value) = @_; print $msg, (defined $value ? '' : 'not '), "defined.\n"; }

    This produces the following output:

    Beginning state: $c is not defined. SV = NULL(0x0) at 0x1f5cec0 REFCNT = 1 FLAGS = () State after printing: $c is not defined. SV = PV(0x1f3de10) at 0x1f5cec0 REFCNT = 1 FLAGS = () PV = 0 0 State after integer operation: $c is not defined. SV = PVNV(0x1f3c0d0) at 0x1f5cec0 REFCNT = 1 FLAGS = () IV = 0 NV = 0 PV = 0 State after assignment: $c is defined. SV = PVNV(0x1f3c0d0) at 0x1f5cec0 REFCNT = 1 FLAGS = (NOK,pNOK) IV = 0 NV = 0 PV = 0 State after assigning undef: $c is not defined. SV = PVNV(0x1a0f0d0) at 0x1a2fec0 REFCNT = 1 FLAGS = () IV = 0 NV = 0 PV = 0

    The meaning of this is a little opaque because it's exposing Perl's internals, but I'll try to explain:

    Beginning state: We have declared $c but have not assigned it a value. We can easily detect that it is not defined. And when we Dump it using Devel::Peek, we can see that the structure represented by the variable $c, located at 0x1f5cec0, contains a null pointer for its payload. This is one of the ways that 'not defined' manifests internally.

    Next we include $c in a print statement. But more importantly, we interpolate it into a string. This would generate an undefined value warning if we had that warning enabled, but we explicitly disabled it. String interpolation is provided by the qq{...} quote like operator (or "..."). This monomorphic operator needs its operand to be a sting, so Perl's polymorphic scalar type morphs into a string. And we can see that this impacted the underlying struct. We still are told that $c is not defined, but we also see that the struct has gained a PV (a pointer value), which is a pointer to a string. The payload is represented by PV(0x192ae10).

    Next we include $c in an integer mathematical operation: 0 + $c. In this case $c isn't being assigned a value, it's just being treated as a number. And in the Dump() output we can see that the structure has morphed again. Now the payload isn't just a PV(...), but a PVNV(...), or Pointer Value / Numeric Value payload structure. Additionally, whereas before we had a PV = 0 field (a 0 pointer to the actual empty string), we now have a PV, IV, and NV field (all of them with =0 because no value has been assigned). IV stands for Integer Value.

    Next we assign an integer to $c by doing this: $c = $c + 0. In this case the undefined value is promoted to its numeric representation, which is 0, so $c = 0 + 0. This would also trigger a warning, but we have suppressed the warning for now. And now if we dump the internals we see that the NOK and pNOK flags are set. This means several things, but most important now is that we are known to Perl to be defined for numeric and stringification purposes.

    Finally, we assign undef to $c. You might think this gets us back to our beginning state, but it doesn't. It retains the previous payload structure, but its contents are cleared, and the "I'm defined as a..." flags (NOK, pNOK) are revoked.

    In many ways this is an oversimplification, but the points I'm trying to get at are that performing operations on undefined values do alter the internal structure of the value in various ways, and as we've seen, it is pretty easy for an undefined value to get promoted to an empty string or a number behind the scenes while remaining undefined outwardly.

    So what happens if you start using uninitialized variables? Not much. It's fine if you do it correctly. It's error prone if you do it incorrectly.

    ARE MY PERL SCRIPTS GOING TO RUN SLIGHTLY FASTER IF I DON'T USE STRICT AND WARNINGS?

    Not really. A script containing only use strict and use warnings, and nothing else loads and compiles about 1/1000th of a second slower. The use of lexical variables as opposed to package globals is not significantly different from a performance standpoint either. Not enough to ever care about. It might be within the margin of error even trying to detect a difference.

    What else happens if I quit using the "warnings" and "strict"?

    The larger and more complex your script becomes, the harder it will become to spot typos, bad assumptions, and other bugs. And if you also stop using lexical variables it will become harder and harder to deal with spooky action at a distance that coincides with the use of globals. Also by not using lexical variables you don't get to benefit from the cool things that lexical scoping provides. Your code remains stuck forever in an unmaintainable state that suffers from not leveraging Perl's capabilities effectively.

    if I refer to A in my function, then when I type "A = 5" it becomes a global variable. But if I initialize it as "var A = 5" then it becomes a temporary variable that exists only within the scope of that function. Is Perl treating variables the same way?

    The semantics are similar in some ways. Variables that are not declared is not the same as variables that are not defined. You might be conflating those two principles. But let's look at what happens when a variable is not declared: When you say $abc = 5, the variable springs into existence as a package global. If you are in package main, then its fully qualified name is $main::abc. This variable exists throughout the program; all modules can access it by using its fully qualified name, or by importing it into their own namespace. It is a global variable accessed within its own package on a "first name basis", and from other packages on a "full name" basis.

    When you say my $abc, you are creating a lexical variable. Its scope is constrained to the life cycle of the lexical block in which it lives. Life cycle is important here; A subroutine's life cycle is from when it starts running until when it stops; the variable gets created, used, and then torn down. The next time the subroutine is called, there is no recollection of previous runs of the same subroutine from the perspective of its internal lexical variables. However, the life cycle of an outer-scope enclosing block may be greater. This provides the powerful tools such as generating closures, and is useful in recursion / reentrance, and so on. If you avoid using lexical variables, you are not using Perl to its most effective capacity, and your scripts will suffer from becoming more unmaintainable. But on the other hand, you can write unmaintainable code even using the best tools any language has to offer.


    Dave

Re: Why use warnings? -w
by trippledubs (Deacon) on Feb 22, 2018 at 14:02 UTC
    Putting -w in the shebang line makes warnings global, but use strict and use warnings are lexically scoped. You can also customize what degree of strictness you want or turn it off inside a scoped block. It's near universally encouraged to use strict and warnings because it's helpful to the programmer, probably why Javascript implemented it also, though Javascript's use strict is not as flexible.
Re: Why use warnings? -w
by Anonymous Monk on Feb 22, 2018 at 14:57 UTC
    I am not sure that these directives affect "speed" at all. And in any case, if you spend even one minute of your time puzzling-out a bug that use of these directives could have pointed-out to you, you've burned up 60 million microseconds, and it will be a very long time before you recover that one minute through faster execution speeds . . . In the grand scheme of things, the computer's time is free – yours is not. You should take advantage of every bug-finding tool that every language offers you.
Re: Why use warnings? -w
by karlgoethebier (Abbot) on Feb 23, 2018 at 11:10 UTC
    "... scripts going to run slightly faster..."

    May be. If you really want to know the truth you could benchmark it.

    But how much time do you waste for debugging if you turn strict and warnings off?

    There is a nice German word for efforts like this (or better: the effect these efforts might have): unwägbar.

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1209716]
Approved by Athanasius
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (3)
As of 2024-04-24 00:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found